home *** CD-ROM | disk | FTP | other *** search
/ SGI Freeware 2002 November / SGI Freeware 2002 November - Disc 2.iso / dist / fw_glimpse.idb / usr / freeware / src / glimpse-3.0 / main.c.z / main.c
C/C++ Source or Header  |  1997-09-09  |  99KB  |  2,986 lines

  1. /* Copyright (c) 1994 Sun Wu, Udi Manber, Burra Gopal.  All Rights Reserved. */
  2. /* bgopal: (1993-4) redesigned/rewritten using agrep's library interface */
  3. #include <sys/param.h>
  4. #include <errno.h>
  5. #include "glimpse.h"
  6. #include "defs.h"
  7. #include <fcntl.h>
  8. #include "checkfile.h"
  9. #include <sys/types.h>
  10. #include <sys/stat.h>
  11. #include <sys/time.h>
  12. #include <sys/file.h>    /* for flock definition */
  13. #if    ISO_CHAR_SET
  14. #include <locale.h>    /* support for 8bit character set */
  15. #endif
  16.  
  17. #define CLIENTSERVER    1
  18. #define USE_MSGHDR    0
  19. #define USE_UNIXDOMAIN    0
  20. #define DEBUG    0
  21.  
  22. #define DEF_SERV_PORT    2001
  23. #define MIN_SERV_PORT    1024
  24. #define MAX_SERV_PORT    30000
  25. #define SERVER_QUEUE_SIZE    10    /* number of requests to buffer up while processing one request = 5 */
  26.  
  27. /* Borrowed from C-Lib */
  28. extern char **environ;
  29. extern int errno;
  30.  
  31. #if    CLIENTSERVER
  32. #include "communicate.c"
  33. #endif    /*CLIENTSERVER*/
  34.  
  35. /* For client-server protocol */
  36. CHAR    SERV_HOST[MAXNAME];
  37. int    SERV_PORT;
  38. char    glimpse_reqbuf[MAX_ARGS*MAX_NAME_LEN];
  39. extern int glimpse_clientdied;    /* set if signal received about dead socket: need agrep variable so that exec() can return quickly */
  40. int    glimpse_reinitialize = 0;
  41.  
  42. /* Borrowed from agrep.c */
  43. extern int D_length;        /* global variable in agrep */
  44. extern int D;            /* global variable in agrep */
  45. extern int pattern_index;
  46. /* These are used for byte level index search */
  47. extern CHAR CurrentFileName[MAX_LINE_LEN];
  48. extern int SetCurrentFileName;
  49. extern int CurrentByteOffset;
  50. extern int SetCurrentByteOffset;
  51. extern int execfd;
  52. extern int  agrep_initialfd;
  53. extern CHAR *agrep_inbuffer;
  54. extern int  agrep_inlen;
  55. extern int  agrep_inpointer;
  56. extern FILE *agrep_finalfp;
  57. extern CHAR *agrep_outbuffer;
  58. extern int  agrep_outlen;
  59. extern int  agrep_outpointer;
  60. extern int glimpse_call;    /* prevent agrep from printing out its usage */
  61. extern int glimpse_isserver;    /* prevent agrep from asking for user input */
  62. int    first_search = 1;    /* intra/interaction in process_query() and glimpse_search() */
  63. #if    ISSERVER && SFS_COMPAT
  64. int    RemoteFiles = 0;    /* Are the files present locally or remotely? If on, then -NQ is automatically added to all search options for each query */
  65. #endif
  66.  
  67. /* Borrowed from index/io.c */
  68. extern int OneFilePerBlock;
  69. extern int StructuredIndex;
  70. extern unsigned int *dest_index_set;
  71. extern unsigned char *dest_index_buf;
  72. extern unsigned int *src_index_set;
  73. extern unsigned char *src_index_buf;
  74. extern unsigned char *merge_index_buf;
  75. extern int mask_int[32];
  76. extern int indexable_char[256];
  77. int test_indexable_char[256];
  78. extern int p_table[MAX_PARTITION];
  79. extern int GMAX_WORD_SIZE;
  80. extern int IndexNumber;        /* used in getword() */
  81. extern int InterpretSpecial;    /* used to "not-split" agrep-regexps */
  82. extern int UseFilters;        /* defined in build_in.c, used for filtering routines in io.c */
  83. extern int ByteLevelIndex;
  84. extern int file_num;
  85. extern int REAL_PARTITION, REAL_INDEX_BUF, MAX_ALL_INDEX, FILEMASK_SIZE;
  86.  
  87. /* Borrowed from get_filename.c */
  88. extern int bigbuffer_size;
  89. extern char *bigbuffer;
  90. extern char *outputbuffer;
  91.  
  92. /* OPTIONS/FLAGS */
  93. int    CONTACT_SERVER = 0;    /* Should client try to call server at all or just process query on its own? */
  94. int    NOBYTELEVEL = 0;    /* Some cases where we cannot do byte level fast-search: ALWAYS 0 if !ByteLevelIndex */
  95. int    OPTIMIZEBYTELEVEL = 0;    /* Some cases where we don't want to do byte level search since number of files is small */
  96. int    GLIMITOUTPUT = 0;    /* max no. of output lines: 0=>infinity=default=nolimit */
  97. int    GLIMITTOTALFILE = 0;    /* max no. of files to match: 0=>infinity=default=nolimit */
  98. int    GLIMITPERFILE = 0;    /* not used in glimpse */
  99. int    GBESTMATCH = 0;        /* Should I change -B to -# where # = no. of errors? */
  100. int    GRECURSIVE = 0;
  101. int    GNOPROMPT = 0;
  102. int    GBYTECOUNT = 0;
  103. int    GPRINTFILENUMBER = 0;
  104. int    GOUTTAIL = 0;
  105. int    GFILENAMEONLY = 0;    /* how to do it if it is an and expression in structured queries */
  106. int    GNOFILENAME=0;
  107. int    MATCHFILE = 0;
  108. int    PRINTATTR = 0;
  109. int    PRINTINDEXLINE = 0;
  110. int    Pat_as_is=0;
  111. int    Only_first=0;        /* Do index search only */
  112. int    PRINTAPPXFILEMATCH=0;    /* Print places in file where match occurs: useful with -b only to analyse the index */
  113. int    GCOUNT=0;        /* print number of matches rather than actual matches: used only when PRINTAPPX = 1 */
  114. int    HINTSFROMUSER=0;    /* The user gives the hints about where we should search (result of adding -EQNgy) */
  115. int    WHOLEFILESCOPE=0;    /* used only when foundattr is NOT set: otherwise, scope is whole file anyway */
  116. int    foundattr=0;        /* set in split.c -- != 0 only when StructuredIndex AND query is structured */
  117.  
  118. /* structured queries */
  119. CHAR    ***attr_vals;        /* matrix of char pointers: row=max #of attributes, col=max possible values */
  120. CHAR    **attr_found;        /* did the expression corr. to each value in attr_vals match? */
  121. ParseTree *GParse;        /* what kind of expression corr. to attr are we looking for */
  122.  
  123. /* arbitrary booleans */
  124. ParseTree terminals[MAXNUM_PAT];    /* parse tree's terminal node pointers pt. to elements of this array; also used outside */ 
  125. char    matched_terminals[MAXNUM_PAT];    /* ...[i] is 1 if i'th terminal matched: used in filter_output and eval_tree */
  126. int    num_terminals;        /* number of terminal patterns */
  127. int    ComplexBoolean=0;    /* 1 if we need to use parse trees and the eval function */
  128.  
  129. /* index search */
  130. CHAR    *pat_list[MAXNUM_PAT];    /* complete words within global pattern */
  131. int    pat_lens[MAXNUM_PAT];    /* their lengths */
  132. int    pat_attr[MAXNUM_PAT];    /* set of attributes */
  133. int    is_mgrep_pat[MAXNUM_PAT];
  134. int    mgrep_pat_index[MAXNUM_PAT];
  135. int    num_mgrep_pat;
  136. CHAR    pat_buf[(MAXNUM_PAT + 2)*MAXPAT];
  137. int    pat_ptr = 0;
  138. extern char INDEX_DIR[MAX_LINE_LEN];
  139. char    TEMP_DIR[MAX_LINE_LEN];
  140. char    indexnumberbuf[256];    /* to read in first few lines of the index */
  141. char    *index_argv[MAX_ARGS];
  142. int    index_argc = 0;
  143. int    bestmatcherrors=0;    /* set during index search, used later on */
  144. int    patindex; 
  145. int    patbufpos = -1;
  146. char    tempfile[MAX_NAME_LEN];
  147.  
  148. /* agrep search */
  149. char    *agrep_argv[MAX_ARGS];
  150. int     agrep_argc = 0;
  151. CHAR    *FileOpt;        /* the option list after -F */
  152. int    fileopt_length;
  153. CHAR    GPattern[MAXPAT];
  154. int    GM;
  155. CHAR    APattern[MAXPAT];
  156. int    AM;
  157. CHAR    GD_pattern[MAXPAT];
  158. int    GD_length;
  159. CHAR    **GTextfiles;
  160. CHAR    **GTextfilenames;
  161. int    *GFileIndex;
  162. int    GNumfiles;
  163. int    GNumpartitions;
  164. CHAR    GProgname[MAXNAME];
  165.  
  166. /* persistent file descriptors */
  167. #if    BG_DEBUG
  168. FILE *debug;             /* file descriptor for debugging output */
  169. #endif    /*BG_DEBUG*/
  170. FILE    *indexfp = NULL;    /* glimpse index */
  171. FILE    *partfp = NULL;        /* glimpse partitions */
  172. FILE    *minifp = NULL;        /* glimpse turbo */
  173. FILE    *nullfp = NULL;        /* to discard output: agrep -s doesn't work properly */
  174. int    svstdin = 0, svstdout = 1, svstderr = 2;
  175.  
  176. /* Index manipulation */
  177. struct offsets **src_offset_table;
  178. struct offsets **multi_dest_offset_table[MAXNUM_PAT];
  179. unsigned int *multi_dest_index_set[MAXNUM_PAT];
  180. extern free_list();
  181. struct stat index_stat_buf, file_stat_buf;
  182.  
  183. /* Direct agrep access for bytelevel-indices */
  184. extern int COUNT, INVERSE, TCOMPRESSED, NOFILENAME, POST_FILTER, OUTTAIL, BYTECOUNT,
  185.     LIMITOUTPUT, LIMITPERFILE, LIMITTOTALFILE, PRINTRECORD, DELIMITER, SILENT, FILENAMEONLY, num_of_matched, prev_num_of_matched, FILEOUT;
  186. CHAR    matched_region[MAX_REGION_LIMIT*2 + MAXPATT*2];
  187. int    RegionLimit=DEFAULT_REGION_LIMIT;
  188.  
  189. /* Returns number of matched records/lines. Uses agrep's options to output stuff nicely */
  190. int
  191. glimpse_search(AM, APattern, GD_length, GD_pattern, realfilename, filename, fileindex, src_offset_table, outfp)
  192.     int        AM;
  193.     unsigned char    APattern[];
  194.     int        GD_length;
  195.     unsigned char    GD_pattern[];
  196.     char        *realfilename;
  197.     char        *filename;
  198.     int        fileindex;
  199.     struct offsets    *src_offset_table[];
  200.     FILE        *outfp;
  201. {
  202.     FILE        *infp;
  203.     char        sig[SIGNATURE_LEN];
  204.     struct offsets    **p1, *tp1;
  205.     CHAR        *text, *curtextend, *curtextbegin, c;
  206.     int        times;
  207.     int        num, ret, totalret = 0;
  208.     int        prevoffset = 0, begininterval = 0, endinterval = -1;
  209.     CHAR        *beginregionptr = 0, *endregionptr = 0;
  210.     int        beginpage = 0, endpage = -1;
  211.     static int    MAXTIMES, MAXPGTIMES, pagesize;
  212.     static int    first_time = 1;
  213.  
  214.     /*
  215.      * If can't open file for read, quit
  216.      * For each offset for that file:
  217.      *    seek to that point
  218.      *    go back until delimiter, go forward until delimiter, output it: MAX_REGION_LIMIT is 16K on either side.
  219.      *    read in units of RegionLimit
  220.      *    before outputting matched record, use options to put prefixes (or use memagrep which does everything?)
  221.      * Algorithm changed: don't read same page in twice.
  222.      */
  223.  
  224.     if (first_time) {
  225.         pagesize = DISKBLOCKSIZE;
  226.         MAXTIMES = ((MAX_REGION_LIMIT / RegionLimit) > 1) ? (MAX_REGION_LIMIT / RegionLimit) : 1;
  227.         MAXPGTIMES = ((MAX_REGION_LIMIT / pagesize) > 1) ? (MAX_REGION_LIMIT / pagesize) : 1;
  228.         first_time = 0;
  229.     }
  230.     /* Safety: must end/begin with delim */
  231.     memcpy(matched_region, GD_pattern, GD_length);
  232.     memcpy(matched_region+MAXPATT+2*MAX_REGION_LIMIT, GD_pattern, GD_length);
  233.     text = &matched_region[MAX_REGION_LIMIT+MAXPATT];
  234.  
  235.     if ((infp = fopen(filename, "r")) == NULL) return 0;
  236. #if    0
  237.     /* Cannot search in .CZ files since offset computations will be incorrect */
  238.     TCOMPRESSED = ON;
  239.     if (!tuncompressible_filename(file_list[i], strlen(file_list[i]))) TCOMPRESSED = OFF;
  240.     num_read = fread(sig, 1, SIGNATURE_LEN, infp);
  241.     if ((TCOMPRESSED == ON) && tuncompressible(sig, num_read)) {
  242.         EASYSEARCH = sig[SIGNATURE_LEN-1];
  243.         if (!EASYSEARCH) {
  244.             fprintf(stderr, "not compressed for easy-search: can miss some matches in: %s\n", CurrentFileName);    /* not filename!!! */
  245.         }
  246.     }
  247.     else TCOMPRESSED = OFF;
  248. #endif    /*0*/
  249.  
  250.     p1 = &src_offset_table[fileindex];
  251.     while (*p1 != NULL) {
  252.         if ( (begininterval <= (*p1)->offset) && (endinterval > (*p1)->offset) ) {    /* already covered this area */
  253. #if    DEBUG
  254.             printf("ignoring %d in [%d,%d]\n", (*p1)->offset, begininterval, endinterval);
  255. #endif    /*DEBUG*/
  256.             tp1 = *p1;
  257.             *p1 = (*p1)->next;
  258.             my_free(tp1, sizeof(struct offsets));
  259.             continue;
  260.         }
  261.  
  262.         TCOMPRESSED = OFF;
  263. #if    1
  264.         if ( (beginpage <= (*p1)->offset) && (endpage >= (*p1)->offset) && (text + ((*p1)->offset - prevoffset) + GD_length < endregionptr)) {
  265.             /* beginregionptr = curtextend - GD_length;    /* prevent next curtextbegin to go behind previous curtextend (!) */
  266.             text += ((*p1)->offset - prevoffset);
  267.             prevoffset = (*p1)->offset;
  268.             if (!((curtextend = forward_delimiter(text, endregionptr, GD_pattern, GD_length, 1)) < endregionptr))
  269.                 goto fresh_read;
  270.             if (!((curtextbegin = backward_delimiter(text, beginregionptr, GD_pattern, GD_length, 0)) > beginregionptr))
  271.                 goto fresh_read;
  272.         }
  273.         else { /* NOT within an area already read: must read another page: if record overlapps page, might read page twice: no time to fix */
  274.         fresh_read:
  275.             prevoffset = (*p1)->offset;
  276.             text = &matched_region[MAX_REGION_LIMIT+MAXPATT];    /* middle: points to occurrence of pattern */
  277.             endpage = beginpage = ((*p1)->offset / pagesize) * pagesize;
  278.             /* endpage = (((*p1)->offset + pagesize) / pagesize) * pagesize */
  279.             endregionptr = beginregionptr = text - ((*p1)->offset - beginpage);    /* overlay physical place starting from this logical point */
  280.             /* endregionptr = text + (endpage - (*p1)->offset); */
  281.             curtextbegin = curtextend = text;
  282.             times = 0;
  283.             while (times < MAXPGTIMES) {
  284.                 fseek(infp, endpage, 0);
  285.                 num = (&matched_region[MAX_REGION_LIMIT*2+MAXPATT] - endregionptr < pagesize) ? (&matched_region[MAX_REGION_LIMIT*2+MAXPATT] - endregionptr) : pagesize;
  286.                 if ((num = fread(endregionptr, 1, num, infp)) <= 0) break;
  287.                 endpage += num;
  288.                 endregionptr += num;
  289.                 if (endregionptr <= text) {
  290.                     curtextend = text;    /* error in value of offset: file was modified and offsets no longer true: your RISK! */
  291.                     break;
  292.                 }
  293.                 if (((curtextend = forward_delimiter(text, endregionptr, GD_pattern, GD_length, 1)) < endregionptr) ||
  294.                     (endregionptr >= &matched_region[MAX_REGION_LIMIT*2 + MAXPATT])) break;
  295.                 times ++;
  296.             }
  297.             times = 0;
  298.             while (times < MAXPGTIMES) {    /* I have already read the initial page since endpage is beginpage initially */
  299.                 if ((curtextbegin = backward_delimiter(text, beginregionptr, GD_pattern, GD_length, 0)) > beginregionptr) break;
  300.                 if (beginpage > 0) {
  301.                     if (beginregionptr - pagesize < &matched_region[MAXPATT]) {
  302.                         if ((num = beginregionptr - &matched_region[MAXPATT]) <= 0) break;
  303.                     }
  304.                     else num = pagesize;
  305.                     beginpage -= num;
  306.                     beginregionptr -= num;
  307.                 }
  308.                 else break;
  309.                 times ++;
  310.                 fseek(infp, beginpage, 0);
  311.                 fread(beginregionptr, 1, num, infp);
  312.             }
  313.         }
  314. #else    /*1*/
  315.         /* Find forward delimiter (including delimiter) */
  316.         times = 0;
  317.         fseek(infp, (*p1)->offset, 0);
  318.         while (times < MAXTIMES) {
  319.             if ((num = fread(text+RegionLimit*times, 1, RegionLimit, infp)) > 0)
  320.                 curtextend = forward_delimiter(text, text+RegionLimit*times+num, GD_pattern, GD_length, 1);
  321.             if ((curtextend < text+RegionLimit*times+num) || (num < RegionLimit)) break;
  322.             times ++;
  323.         }
  324.         /* Find backward delimiter (including delimiter) */
  325.         times = 0;
  326.         while (times < MAXTIMES) {
  327.             num = ((*p1)->offset - RegionLimit*(times+1)) > 0 ? ((*p1)->offset - RegionLimit*(times+1)) : 0;
  328.             fseek(infp, num, 0);
  329.             if (num > 0) {
  330.                 fread(text-RegionLimit*(times+1), 1, RegionLimit, infp);
  331.                 curtextbegin = backward_delimiter(text, text-RegionLimit*(times+1), GD_pattern, GD_length, 0);
  332.             }
  333.             else {
  334.                 fread(text-RegionLimit*times-(*p1)->offset, 1, (*p1)->offset, infp);
  335.                 curtextbegin = backward_delimiter(text, text-RegionLimit*times-(*p1)->offset, GD_pattern, GD_length, 0);
  336.             }
  337.             if ((num <= 0) || (curtextbegin > text-RegionLimit*(times+1))) break;
  338.             times ++;
  339.         }
  340. #endif    /*1*/
  341.  
  342.         /* set interval and delete the entry */
  343.         begininterval = (*p1)->offset - (text - curtextbegin);
  344.         endinterval = (*p1)->offset + (curtextend - text); 
  345.  
  346.         if (strncmp(curtextbegin, GD_pattern, GD_length)) {
  347.             /* always pass enclosing delimiters to agrep; since we have seen text before curtextbegin + we have space, we can overwrite */
  348.             memcpy(curtextbegin - GD_length, GD_pattern, GD_length);
  349.             curtextbegin -= GD_length;
  350.         }
  351. #if    DEBUG
  352.         c = *curtextend;
  353.         *curtextend = '\0';
  354.         printf("%s [%d < %d < %d], text = %d: %s\n", CurrentFileName, begininterval, (*p1)->offset, endinterval, text, curtextbegin);
  355.         *curtextend = c;
  356. #endif    /*DEBUG*/
  357.  
  358.         tp1 = *p1;
  359.         *p1 = (*p1)->next;
  360.         my_free(tp1, sizeof(struct offsets));
  361.         if (curtextend <= curtextbegin) continue;    /* error in offsets/delims */
  362.  
  363.         /*
  364.          * Don't call memagrep since that is heavy weight. Call exec
  365.          * directly after doing agrep_search()'s preprocessing here.
  366.          * PS: can add agrep variable not to do delim search if called from here
  367.          * since that prevents unnecessarily scanning the buffer for the 2nd time.
  368.          */
  369.         CurrentByteOffset = begininterval+1;
  370.         SetCurrentByteOffset = 1;
  371.         first_search = 1;
  372.         if (first_search) {
  373.             if ((ret = memagrep_search(AM, APattern, curtextend-curtextbegin, curtextbegin, 0, outfp)) > 0)
  374.                 totalret ++; /* += ret */
  375.              else if ((ret < 0) && (errno == AGREP_ERROR)) {
  376.                 fclose(infp);
  377.                 return -1;
  378.             }
  379.             first_search = 0;
  380.         }
  381.         else {    /* All agrep globals are properly set: has a bug because agrep's globals aren't properly reinitialized without agrep_search :-( */
  382.             agrep_finalfp = (FILE *)outfp;
  383.             agrep_outlen = 0;
  384.             agrep_outbuffer = NULL;
  385.             agrep_outpointer = 0;
  386.             execfd = agrep_initialfd = -1;
  387.             agrep_inbuffer = curtextbegin;
  388.             agrep_inlen = curtextend - curtextbegin;
  389.             agrep_inpointer = 0;
  390.             if ((ret = exec(-1, NULL)) > 0)
  391.                 totalret ++; /* += ret; */
  392.              else if ((ret < 0) && (errno == AGREP_ERROR)) {
  393.                 fclose(infp);
  394.                 return -1;
  395.             }
  396.         }
  397.  
  398.         if (((LIMITOUTPUT > 0) && (LIMITOUTPUT <= num_of_matched)) ||
  399.             ((LIMITPERFILE > 0) && (LIMITPERFILE <= num_of_matched - prev_num_of_matched))) break;    /* done */
  400.         if ((totalret > 0) && FILENAMEONLY) break;
  401.     }
  402.  
  403.     SetCurrentByteOffset = 0;
  404.     fclose(infp);
  405.     if (totalret > 0) {    /* dirty solution: must handle part of agrep here */
  406.         if (COUNT && !FILEOUT) {
  407.             if(!NOFILENAME) fprintf(outfp, "%s: %d\n", CurrentFileName, totalret);
  408.             else fprintf(outfp, "%d\n", totalret);
  409.         }
  410.         else if (FILEOUT) {
  411.             file_out(realfilename);
  412.         }
  413.     }
  414.     return totalret;
  415. }
  416.  
  417. read_index(indexdir)
  418. char    indexdir[MAXNAME];
  419. {
  420.     char    *home;
  421.     char    s[MAXNAME];
  422.     int    ret;
  423.  
  424.     if (indexdir[0] == '\0') {
  425.         if ((home = (char *)getenv("HOME")) == NULL) {
  426.             getcwd(indexdir, MAXNAME-1);
  427.             fprintf(stderr, "using working-directory '%s' to locate index\n", indexdir);
  428.         }
  429.         else strncpy(indexdir, home, MAXNAME);
  430.     }
  431.     ret = chdir(indexdir);
  432.     if (getcwd(INDEX_DIR, MAXNAME-1) == NULL) strcpy(INDEX_DIR, indexdir);
  433.     if (ret < 0) {
  434.         fprintf(stderr, "using working-directory '%s' to locate index\n", INDEX_DIR);
  435.     }
  436.  
  437.     sprintf(s, "%s", INDEX_FILE);
  438.     indexfp = fopen(s, "r");
  439.     if(indexfp == NULL) {
  440.         fprintf(stderr, "can't open glimpse index-file %s/%s\n", INDEX_DIR, INDEX_FILE);
  441.         fprintf(stderr, "(use -H to give an index-directory or run 'glimpseindex' to make an index)\n");
  442.         return -1;
  443.     }
  444.     if (stat(s, &index_stat_buf) == -1) {
  445.         fprintf(stderr, "can't stat %s/%s\n", INDEX_DIR, s);
  446.         fclose(indexfp);
  447.         return -1;
  448.     }
  449.  
  450.     sprintf(s, "%s", P_TABLE);
  451.     partfp = fopen(s, "r");
  452.     if(partfp == NULL) {
  453.         fprintf(stderr, "can't open glimpse partition-table %s/%s\n", INDEX_DIR, P_TABLE);
  454.         fprintf(stderr, "(use -H to specify an index-directory or run glimpseindex to make an index)\n");
  455.         return -1;
  456.     }
  457.  
  458.     /* Get options */
  459. #if    BG_DEBUG
  460.     debug = fopen(DEBUG_FILE, "w+");
  461.     if(debug == NULL) {
  462.         fprintf(stderr, "can't open file %s/%s, errno=%d\n", INDEX_DIR, DEBUG_FILE, errno);
  463.         return(-1);
  464.     }
  465. #endif    /*BG_DEBUG*/
  466.     fgets(indexnumberbuf, 256, indexfp);
  467.     if(strstr(indexnumberbuf, "1234567890")) IndexNumber = ON;
  468.     else IndexNumber = OFF;
  469.     fscanf(indexfp, "%%%d\n", &OneFilePerBlock);
  470.     if (OneFilePerBlock < 0) {
  471.         ByteLevelIndex = ON;
  472.         OneFilePerBlock = -OneFilePerBlock;
  473.     }
  474.     else if (OneFilePerBlock == 0) {
  475.         GNumpartitions = get_table(P_TABLE, p_table, MAX_PARTITION, 0);
  476.     }
  477.     fscanf(indexfp, "%%%d\n", &StructuredIndex);
  478.     /* Set WHOLEFILESCOPE for do-it-yourself request processing at client */
  479.     WHOLEFILESCOPE = 1;
  480.     if (StructuredIndex <= 0) {
  481.         WHOLEFILESCOPE = 0;
  482.         StructuredIndex = 0;
  483.         PRINTATTR = 0;    /* doesn't make sense: must not go into filter_output */
  484.     }
  485.     else if (-1 == (StructuredIndex = attr_load_names(ATTRIBUTE_FILE))) {
  486.         fprintf(stderr, "error in reading attribute file %s/%s\n", INDEX_DIR, ATTRIBUTE_FILE);
  487.         return(-1);
  488.     }
  489. #if    BG_DEBUG
  490.     fprintf(debug, "buf = %s OneFilePerBlock=%d StructuredIndex=%d\n", indexnumberbuf, OneFilePerBlock, StructuredIndex);
  491. #endif    /*BG_DEBUG*/
  492.     sprintf(s, "%s", MINI_FILE);
  493.     minifp = fopen(s, "r");
  494.     /* if (minifp==NULL && OneFilePerBlock) fprintf(stderr, "Can't open for reading: %s/%s --- cannot do very fast search\n", INDEX_DIR, MINI_FILE); */
  495.     if (OneFilePerBlock && glimpse_isserver && (minifp != NULL)) read_mini(indexfp, minifp);
  496.     read_filenames();
  497.  
  498.     /* Once IndexNumber info is available */
  499.     set_indexable_char(indexable_char);
  500.     set_indexable_char(test_indexable_char);
  501.     set_special_char(indexable_char);
  502.     return 0;
  503. }
  504.  
  505. #define CLEANUP \
  506. {\
  507.     int    q, k;\
  508.     if (indexfp != NULL) fclose(indexfp);\
  509.     if (partfp != NULL) fclose(partfp);\
  510.     if (minifp != NULL) fclose(minifp);\
  511.     if (nullfp != NULL) fclose(nullfp);\
  512.     indexfp = partfp = minifp = nullfp = NULL;\
  513.     if (ByteLevelIndex) {\
  514.         if (src_offset_table != NULL) for (k=0; k<OneFilePerBlock; k++) {\
  515.             free_list(&src_offset_table[k]);\
  516.         }\
  517.         for (q=0; q<MAXNUM_PAT; q++) {\
  518.             if (multi_dest_offset_table[q] != NULL) for (k=0; k<OneFilePerBlock; k++) {\
  519.             free_list(&multi_dest_offset_table[q][k]);\
  520.             }\
  521.         }\
  522.     }\
  523.     if (StructuredIndex) {\
  524.         attr_free_table();\
  525.     }\
  526.     destroy_filename_hashtable();\
  527. }
  528.  
  529. /* Called whenever we get SIGUSR2/SIGHUP (at the end of process_query()) */
  530. reinitialize_server(argc, argv)
  531.     int    argc;
  532.     char    **argv;
  533. {
  534.     int    i, fd;
  535.     CLEANUP;
  536. #if    0
  537.     init_filename_hashtable();
  538.     region_initialize();
  539.     indexfp = partfp = minifp = nullfp = NULL;
  540.     if ((nullfp = fopen("/dev/null", "w")) == NULL) {
  541.         return(-1);
  542.     }
  543.     src_offset_table = NULL;
  544.     for (i=0; i<MAXNUM_PAT; i++) multi_dest_offset_table[i] = NULL;
  545.     if (-1 == read_index(INDEX_DIR)) return(-1);
  546. #if    0
  547. #ifndef    LOCK_UN
  548. #define LOCK_UN    8
  549. #endif
  550.     if ((fd = open(INDEX_DIR, O_RDONLY)) == -1) return -1;
  551.     flock(fd, LOCK_UN);
  552.     close(fd);
  553. #endif
  554.     return 0;
  555. #else
  556.     return execve(argv[0], argv, environ);
  557. #endif
  558. }
  559.  
  560. /* MUST CARE IF PIPE/SOCKET IS BROKEN! ALSO SIGUSR1 (hardy@cs.colorado.edu) => QUIT CURRENT REQUEST. */
  561. int ignore_signal[32] = {    0,
  562.             0, 0, 1, 1, 1, 1, 1, 1,    /* all the tracing stuff: since default action is to dump core */
  563.             0, 0, 0, 0, 0, 0, 0, 0,
  564.             0, 0, 0, 0, 0, 0, 0, 0,
  565.             0, 0, 0, 0, 1, 0, 0 };    /* resource lost: since default action is to dump core */
  566.  
  567. /* S.t. sockets don't persist: they sometimes have a bad habit of doing so */
  568. void
  569. cleanup()
  570. {
  571.     int    i;
  572.  
  573.     /* ^C in the middle of a client call */
  574.     if (svstderr != 2) {
  575.         close(2);
  576.         dup(svstderr);
  577.     }
  578.     fprintf(stderr, "server cleaning up...\n");
  579.     CLEANUP;
  580.     for (i=0; i<64; i++) close(i);
  581.     exit(3);
  582. }
  583.  
  584. void reinitialize(s)
  585. int s;
  586. {
  587.     /* To force main-while loop call reinitialize_server() after do_select() */
  588.     glimpse_reinitialize = 1;
  589. #ifdef __svr4__
  590.     /* Solaris 2.3 insists that you reset the signal handler */
  591.     (void)signal(s, reinitialize);
  592. #endif
  593. }
  594.  
  595. #define QUITREQUESTMSG "glimpseserver: aborting request...\n"
  596. /* S.t. one request doesn't keep server occupied too long, when client already quits */
  597. void quitrequest(s)
  598. int s;
  599. {
  600.     /*
  601.      * Don't write onto stderr, since 2 is duped to sockfd => can cause recursive signal!
  602.      * Also, don't print error message more than once for quitting one request. The
  603.      * server receives signals for EVERY write it attempts when it finds a match: I could
  604.      * not find a way to prevent it, but agrep/bitap.c/fill_buf() was fixed to limit it.
  605.      * -- bg on 16th Feb 1995
  606.      */
  607.     if (!glimpse_clientdied && (s != SIGUSR1))    /* USR1 is a "friendly" cleanup message */
  608.         write(svstderr, QUITREQUESTMSG, strlen(QUITREQUESTMSG));
  609.  
  610.     glimpse_clientdied = 1;
  611. #ifdef __svr4__
  612.     /* Solaris 2.3 insists that you reset the signal handler */
  613.     (void)signal(s, quitrequest);
  614. #endif
  615. }
  616.  
  617. main(argc, argv)
  618. int argc;
  619. char *argv[];
  620. {
  621.     int    ret, tried = 0;
  622.     char    indexdir[MAXNAME];
  623.     char    **oldargv = argv;
  624.     int    oldargc = argc;
  625. #if    CLIENTSERVER
  626.     int    sockfd, newsockfd, clilen, len, clpid;
  627.     int    clout;
  628. #if    USE_UNIXDOMAIN
  629.     struct sockaddr_un cli_addr, serv_addr;
  630. #else    /*USE_UNIXDOMAIN*/
  631.     struct sockaddr_in cli_addr, serv_addr;
  632.     struct hostent *hp;
  633. #endif    /*USE_UNIXDOMAIN*/
  634.     int    cli_len;
  635.     int    clargc;
  636.     char    **clargv;
  637.     int    clstdin, clstdout, clstderr;
  638.     int    i;
  639.     char    array[4];
  640.     char    *p, c;
  641. #endif    /*CLIENTSERVER*/
  642.     int    quitwhile;
  643.  
  644. #if    ISO_CHAR_SET
  645.     setlocale(LC_ALL,"");       /* support for 8bit character set: ew@senate.be, Henrik.Martin@eua.ericsson.se */
  646. #endif
  647. #if    CLIENTSERVER && ISSERVER
  648.     glimpse_isserver = 1;    /* I am the server */
  649. #else    /*CLIENTSERVER && ISSERVER*/
  650.     if (argc <= 1) return(usage());    /* Client nees at least 1 argument */
  651. #endif    /*CLIENTSERVER && ISSERVER*/
  652.  
  653. #define RETURNMAIN(val)\
  654. {\
  655.     CLEANUP;\
  656.     return (val);\
  657. }
  658.  
  659.     /* once-only initialization */
  660.     init_filename_hashtable();
  661.     src_offset_table = NULL;
  662.     for (i=0; i<MAXNUM_PAT; i++) multi_dest_offset_table[i] = NULL;
  663.     gethostname(SERV_HOST, MAXNAME - 2);
  664.     SERV_PORT = DEF_SERV_PORT;
  665.     srand(getpid());
  666.     umask(077);
  667.     strcpy(&GProgname[0], argv[0]);
  668.     region_initialize();
  669.     indexfp = partfp = minifp = nullfp = NULL;
  670.     if ((nullfp = fopen("/dev/null", "w")) == NULL) {
  671.         fprintf(stderr, "%s: cannot open for writing: /dev/null, errno=%d\n", argv[0], errno);
  672.         RETURNMAIN(-1);
  673.     }
  674.     InterpretSpecial = ON;
  675.     GMAX_WORD_SIZE = MAXPAT;
  676.  
  677. #if    CLIENTSERVER
  678. #if    !ISSERVER
  679.     /* Check if client has too many arguments: then it is surely running as agrep since I have < half those options! */
  680.     if (argc > MAX_ARGS) goto doityourself;
  681. #endif    /*!ISSERVER*/
  682.  
  683.     while((--argc > 0) && (*++argv)[0] == '-' ) {
  684.         p = argv[0] + 1;    /* ptr to first character after '-' */
  685.         c = *(argv[0]+1);
  686.         quitwhile = OFF;
  687.         while (!quitwhile && (*p != '\0')) {
  688.             c = *p;
  689.             switch(c) {
  690.             /* Look for -H option at server (only one that makes sense); if client has a -H, then it goes to doityourself */
  691.             case 'H' :
  692.                 if (*(p + 1) == '\0') {/* space after - option */
  693.                     if (argc <= 1) {
  694.                         fprintf(stderr, "%s: a directory name must follow the -H option\n", GProgname);
  695.                         RETURNMAIN(usageS());
  696.                     }
  697.                     argv ++;
  698.                     strcpy(indexdir, argv[0]);
  699.                     argc --;
  700.                 }
  701.                 else {
  702.                     strcpy(indexdir, p+1);
  703.                 }
  704.                 quitwhile = ON;
  705.                 break;
  706.  
  707.             /* Recognized by both client and server */
  708.             case 'J' :
  709.                 if (*(p + 1) == '\0') {/* space after - option */
  710.                     if (argc <= 1) {
  711.                         fprintf(stderr, "%s: the server host name must follow the -J option\n", GProgname);
  712. #if    ISSERVER
  713.                         RETURNMAIN(usageS());
  714. #else    /*ISSERVER*/
  715.                         RETURNMAIN(usage());
  716. #endif    /*ISSERVER*/
  717.                     }
  718.                     argv ++;
  719.                     strcpy(SERV_HOST, argv[0]);
  720.                     argc --;
  721.                 }
  722.                 else {
  723.                     strcpy(SERV_HOST, p+1);
  724.                 }
  725.                 quitwhile = ON;
  726.                 break;
  727.  
  728.             /* Recognized by both client and server */
  729.             case 'K' :
  730.                 if (*(p + 1) == '\0') {/* space after - option */
  731.                     if (argc <= 1) {
  732.                         fprintf(stderr, "%s: the server port must follow the -C option\n", GProgname);
  733. #if    ISSERVER
  734.                         RETURNMAIN(usageS());
  735. #else    /*ISSERVER*/
  736.                         RETURNMAIN(usage());
  737. #endif    /*ISSERVER*/
  738.                     }
  739.                     argv ++;
  740.                     SERV_PORT = atoi(argv[0]);
  741.                     argc --;
  742.                 }
  743.                 else {
  744.                     SERV_PORT = atoi(p+1);
  745.                 }
  746.                 if ((SERV_PORT < MIN_SERV_PORT) || (SERV_PORT > MAX_SERV_PORT)) {
  747.                     fprintf(stderr, "Bad server port %d: must be in [%d, %d]: using default %d\n",
  748.                         SERV_PORT, MIN_SERV_PORT, MAX_SERV_PORT, DEF_SERV_PORT);
  749.                     SERV_PORT = DEF_SERV_PORT;
  750.                 }
  751.                 quitwhile = ON;
  752.                 break;
  753.  
  754. #if    ISSERVER
  755. #if    SFS_COMPAT
  756.             case 'R' :
  757.                 RemoteFiles = ON;
  758.                 break;
  759.  
  760.             case 'Z' :
  761.                 /* No op */
  762.                 break;
  763. #endif
  764.             /* server cannot recognize any other option */
  765.             default :
  766.                 fprintf(stderr, "%s: server cannot recognize option: '%s'\n", GProgname, p);
  767.                 RETURNMAIN(usageS());
  768. #else    /*ISSERVER*/
  769.  
  770.             /* These have 1 argument each, so must do quitwhile */
  771.             case 'd' :
  772.             case 'e' :
  773.             case 'k' :
  774.             case 'D' :
  775.             case 'F' : 
  776.             case 'I' :
  777.             case 'L' :
  778.             case 'R' :
  779.             case 'S' :
  780.             case 'T' :
  781.             case 'Y' :
  782.                 if (argv[0][2] == '\0') {/* space after - option */
  783.                     if(argc <= 1) {
  784.                         fprintf(stderr, "%s: the '-%c' option must have an argument\n", GProgname, c);
  785.                         RETURNMAIN(usage());
  786.                     }
  787.                     argv++;
  788.                     argc--;
  789.                 }
  790.                 quitwhile = ON;
  791.                 break;
  792.  
  793.             /* These are illegal */
  794.             case 'f' :
  795.             case 'm' :
  796.             case 'p' :
  797.             case 'v' :
  798.                 fprintf(stderr, "%s: illegal option: '-%c'\n", GProgname, c);
  799.                 RETURNMAIN(usage());
  800.  
  801.             /* They can't be patterns and filenames since they start with a -, these don't have arguments */
  802.             case 'a' :
  803.             case 'b' :
  804.             case 'c' :
  805.             case 'h' :
  806.             case 'i' :
  807.             case 'l' :
  808.             case 'n' :
  809.             case 'o' :
  810.             case 'q' :
  811.             case 'r' :
  812.             case 's' :
  813.             case 't' :
  814.             case 'u' :
  815.             case 'g' :
  816.             case 'w' :
  817.             case 'x' :
  818.             case 'y' :
  819.             case 'z' :
  820.             case 'A' :
  821.             case 'B' :
  822.             case 'E' :
  823.             case 'G' :
  824.             case 'M' :
  825.             case 'N' :
  826.             case 'O' :
  827.             case 'P' :
  828.             case 'Q' :
  829.             case 'U' :
  830.             case 'W' :
  831.             case 'Z' :
  832.                 break;
  833.  
  834.             case 'C':
  835.                 CONTACT_SERVER = 1;
  836.                 break;
  837.  
  838.             case 'V' :
  839.                 printf("\nThis is glimpse version %s, %s.\n\n", GLIMPSE_VERSION, GLIMPSE_DATE);
  840.                 RETURNMAIN(0);
  841.  
  842.             default :
  843.                 if (isdigit(c)) quitwhile = ON;
  844.                 else {
  845.                     fprintf(stderr, "%s: illegal option: '-%c'\n", GProgname, c);
  846.                     RETURNMAIN(usage());
  847.                 }
  848.                 break;
  849. #endif    /*ISSERVER*/
  850.             } /* switch(c) */
  851.             p ++;
  852.         }
  853.     }
  854.  
  855. #if    !ISSERVER
  856.     /* Next arg must be the pattern: Check if the user wants to run the client as agrep, or doesn't want to contact the server */
  857.     if ((argc > 1) || (!CONTACT_SERVER)) goto doityourself;
  858. #endif    /*!ISSERVER*/
  859.  
  860.     argv = oldargv;
  861.     argc = oldargc;
  862. #endif    /*CLIENTSERVER*/
  863.  
  864. #if    ISSERVER && CLIENTSERVER
  865.     if (-1 == read_index(indexdir)) RETURNMAIN(ret);
  866.     for (i=0; i<32; i++)
  867.         if (ignore_signal[i]) signal(i, SIG_IGN);
  868.     signal(SIGHUP, cleanup);
  869.     signal(SIGINT, cleanup);
  870.     if (((void (*)())-1 == signal(SIGPIPE, quitrequest)) ||
  871.         ((void (*)())-1 == signal(SIGUSR1, quitrequest)) ||
  872. #ifndef    SCO
  873.         ((void (*)())-1 == signal(SIGURG, quitrequest)) ||
  874. #endif
  875.         ((void (*)())-1 == signal(SIGUSR2, reinitialize)) ||
  876.         ((void (*)())-1 == signal(SIGHUP, reinitialize))) {
  877.         /* Check for return values here since they ensure reliability */
  878.         fprintf(stderr, "glimpseserver: Unable to install signal-handlers.\n");
  879.         RETURNMAIN(-1);
  880.     }
  881.  
  882. #if    USE_UNIXDOMAIN
  883.     if ((sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
  884.         fprintf(stderr, "server cannot open socket for communication.\n");
  885.         RETURNMAIN(-1);
  886.     }
  887.     unlink("/tmp/.glimpse_server");
  888.     memset((char *)&serv_addr, '\0', sizeof(serv_addr));
  889.     serv_addr.sun_family = AF_UNIX;
  890.     strcpy(serv_addr.sun_path, "/tmp/.glimpse_server");    /* < 108 ! */
  891.     len = strlen(serv_addr.sun_path) + sizeof(serv_addr.sun_family);
  892. #else    /*USE_UNIXDOMAIN*/
  893.     if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
  894.         perror("glimpseserver: Cannot create socket");
  895.         RETURNMAIN(-1);
  896.     }
  897.     memset((char *)&serv_addr, '\0', sizeof(serv_addr));
  898.         serv_addr.sin_family = AF_INET;
  899.     serv_addr.sin_port = htons(SERV_PORT);
  900. #if    0
  901.     /* use host-names not internet style d.d.d.d notation */
  902.     serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
  903. #else
  904.     /* 
  905.      * We only want to accept connections from glimpse clients 
  906.      * on the SERV_HOST, do not use INADDR_ANY!
  907.      */
  908.     if ((hp = gethostbyname(SERV_HOST)) == NULL) {
  909.         perror("glimpseserver: Cannot resolve host");
  910.         RETURNMAIN(-1);
  911.     }
  912.     memcpy((caddr_t)&serv_addr.sin_addr, hp->h_addr, hp->h_length);
  913. #endif    /*0*/
  914.     len = sizeof(serv_addr);
  915. #endif    /*USE_UNIXDOMAIN*/
  916.  
  917.     if (bind(sockfd, (struct sockaddr *)&serv_addr, len) < 0) {
  918.         perror("glimpseserver: Cannot bind to socket");
  919.         RETURNMAIN(-1);
  920.     }
  921.     listen(sockfd, SERVER_QUEUE_SIZE);
  922.  
  923.     printf("glimpseserver: On-line (pid = %d, port = %d) waiting for request...\n", getpid(), SERV_PORT);
  924.     fflush(stdout);    /* must fflush to print on server stdout */
  925.     while (1) {
  926.         /*
  927.          *  Spin until sockfd is ready to do a non-blocking accept(2).
  928.          *  We only wait for 15 seconds, because SunOS may
  929.          *  swap us out if we block for 20 seconds or more.
  930.          *  -- Courtesy: Darren Hardy, hardy@cs.colorado.edu
  931.          */
  932.         if ((ret = do_select(sockfd, 15)) == 0) {
  933.             if ((errno == EINTR) && glimpse_reinitialize) {
  934.                 glimpse_reinitialize = 0;
  935.                 CLEANUP;
  936.                 close(sockfd);
  937.                 sleep(IC_PORTRELEASE);
  938.                 reinitialize_server(oldargc, oldargv);
  939.             }
  940.             continue;
  941.         }
  942.         else if (ret != 1) continue;
  943.  
  944.         /* get parameters */
  945.         ret = 0;
  946.         clargc = 0;
  947.         clargv = NULL;
  948.         cli_len = sizeof(cli_addr);
  949.         if ((newsockfd = accept(sockfd, &cli_addr, &cli_len)) < 0) continue;
  950.         if (getreq(newsockfd, glimpse_reqbuf, &clstdin, &clstdout, &clstderr, &clargc, &clargv, &clpid) < 0) {
  951.             ret = -1;
  952. #if    DEBUG
  953.             printf("getreq errno: %d\n", errno);
  954. #endif    /*DEBUG*/
  955.             goto end_process;
  956.         }
  957.  
  958. #if    DEBUG
  959.         printf("server processing request on %x\n", newsockfd);
  960. #endif    /*DEBUG*/
  961.         /*
  962.          * Server doesn't wait for response, no point using
  963.         svstdin = dup(0);
  964.         close(0);
  965.         dup(clstdin);
  966.         close(clstdin);
  967.          */
  968.         /*
  969.          * This is wrong since clstderr == clstdout!
  970.         svstdout = dup(1);
  971.         close(1);
  972.         dup(clstdout);
  973.         close(clstdout);
  974.         svstderr = dup(2);
  975.         close(2);
  976.         dup(clstderr);
  977.         close(clstderr);
  978.         */
  979.         svstdout = dup(1);
  980.         svstderr = dup(2);
  981.         close(1);
  982.         close(2);
  983.         dup(clstdout);
  984.         dup(clstderr);
  985.         close(clstdout);
  986.         close(clstderr);
  987.  
  988.                         /*
  989.              * IMPORTANT: Unbuffered I/O to the client!
  990.                          * Done for Harvest since partial results might be
  991.                          * needed and fflush will not flush partial results
  992.                          * to the client if we type ^C and kill it: it puts
  993.                          * them into /dev/null. This way, output is unbuffered
  994.                          * and the client sees at least some results if killed.
  995.                          */
  996.                         setbuf(stdout, NULL);
  997.                         setbuf(stderr, NULL);
  998.  
  999.             glimpse_call = 0;
  1000.             glimpse_clientdied = 0;
  1001.             ret = process_query(clargc, clargv, newsockfd);
  1002.         /*
  1003.          * Server doesn't wait for response, no point using
  1004.         close(0);
  1005.         dup(svstdin);
  1006.         close(svstdin);
  1007.         svstdin = 0;
  1008.          */
  1009.         if (glimpse_clientdied) {
  1010.             /*
  1011.              * This code is *ONLY* used as a safety net now.  
  1012.              * The old problem was that users would see portions 
  1013.              * of previous (and usually) unrelated queries!
  1014.              * glimpseserver now uses unbuffered I/O to the
  1015.              * client so all previous fwrite's to now are
  1016.              * gone.  But since this is such a nasty problem
  1017.              * we flush stdout to /dev/null just in case.
  1018.              */
  1019.             clout = open("/dev/null", O_WRONLY);
  1020.             close(1);
  1021.             dup(clout);
  1022.             close(clout);
  1023.             fflush(stdout);
  1024.         } 
  1025.  
  1026.         /* Restore svstdout and svstdout to stdout/stderr */
  1027.         close(1);
  1028.         dup(svstdout);
  1029.         close(svstdout);
  1030.         svstdout = 1;
  1031.         close(2);
  1032.         dup(svstderr);
  1033.         close(svstderr);
  1034.         svstderr = 2;
  1035.  
  1036.     end_process:
  1037. #if    USE_MSGHDR
  1038.         /* send reply and cleanup */
  1039.         array[0] = (ret & 0xff000000) >> 24;
  1040.         array[1] = (ret & 0xff0000) >> 16;
  1041.         array[2] = (ret & 0xff00) >> 8;
  1042.         array[3] = (ret & 0xff);
  1043.         writen(newsockfd, array, 4);
  1044. #endif    /*USE_MSGHDR*/
  1045. #if    DEBUG
  1046.         write(1, "done\n", 5);
  1047. #endif    /*DEBUG*/
  1048.         for (i=0; i<clargc; i++)
  1049.             if (clargv[i] != NULL) my_free(clargv[i], 0);
  1050.         if (clargv != NULL) my_free(clargv, 0);
  1051.         close(newsockfd);    /* if !USE_MSGHDR, client directly reads from socket and writes onto stdout until EOF */
  1052.     }
  1053. #else    /*ISSERVER && CLIENTSERVER*/
  1054.  
  1055. #if    CLIENTSERVER
  1056. trynewsocket:
  1057. #if    USE_UNIXDOMAIN
  1058.     if ((sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
  1059.         perror("socket");
  1060.         goto doityourself;
  1061.     }
  1062.     memset((char *)&serv_addr, '\0', sizeof(serv_addr));
  1063.     serv_addr.sun_family = AF_UNIX;
  1064.     strcpy(serv_addr.sun_path, "/tmp/.glimpse_server");    /* < 108 ! */
  1065.     len = strlen(serv_addr.sun_path) + sizeof(serv_addr.sun_family);
  1066. #else    /*USE_UNIXDOMAIN*/
  1067.     if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
  1068.         perror("socket");
  1069.         goto doityourself;
  1070.     }
  1071.     serv_addr.sin_family = AF_INET;
  1072.     serv_addr.sin_port = htons(SERV_PORT);
  1073. #if    0
  1074.     /* use host-names not internet style d.d.d.d notation */
  1075.     serv_addr.sin__addr.s_addr = inet_addr(SERV_HOST);
  1076. #else    /*0*/
  1077.     if ((hp = gethostbyname(SERV_HOST)) == NULL) {
  1078.         fprintf(stderr, "gethostbyname (%s) failed\n", SERV_HOST);
  1079.         goto doityourself;
  1080.     }
  1081.     memcpy((caddr_t)&serv_addr.sin_addr, hp->h_addr, hp->h_length);
  1082. #endif    /*0*/
  1083.     len = sizeof(serv_addr);
  1084. #endif    /*USE_UNIXDOMAIN*/
  1085.  
  1086.     if (connect(sockfd, (struct sockaddr *)&serv_addr, len) < 0) {
  1087.                 char errbuf[4096];
  1088.                 sprintf(errbuf, "glimpse: Cannot contact glimpseserver: %s, port %d:", SERV_HOST, SERV_PORT);
  1089.                 perror(errbuf);
  1090.         /* perror(SERV_HOST); */
  1091. #if    DEBUG
  1092.         printf("connect errno: %d\n", errno);
  1093. #endif    /*DEBUG*/
  1094.         close(sockfd);
  1095.         if ((errno == ECONNREFUSED) && (tried < 4)) {
  1096.             tried ++;
  1097.             goto trynewsocket;
  1098.         }
  1099.         goto doityourself;
  1100.     }
  1101.  
  1102.     if (sendreq(sockfd, glimpse_reqbuf, fileno(stdin), fileno(stdout), fileno(stderr), argc, argv, getpid()) < 0) {
  1103.         perror("sendreq");
  1104. #if    DEBUG
  1105.         printf("sendreq errno: %d\n", errno);
  1106. #endif    /*DEBUG*/
  1107.         close(sockfd);
  1108.         goto doityourself;
  1109.     }
  1110.  
  1111. #if    USE_MSGHDR
  1112.     if (readn(sockfd, array, 4) != 4) {
  1113.         close(sockfd);
  1114.         goto doityourself;
  1115.     }
  1116.     ret = (array[0] << 24) + (array[1] << 16) + (array[2] << 8) + array[3];
  1117. #else    /*USE_MSGHDR*/
  1118. {
  1119.     /* 
  1120.      *  Dump everything the server writes into the socket onto 
  1121.      *  stdout until EOF/error.  Do this in a way so that *everything*
  1122.      *  the server sends is dumped to stdout by the client.  The
  1123.      *  client might die suddenly via ^C or SIGTERM, but we still
  1124.      *  want the results.
  1125.      */
  1126.     char tmpbuf[1024];
  1127.     int n;
  1128.  
  1129.     while ((n = read(sockfd, tmpbuf, 1024)) > 0) {
  1130.         write(fileno(stdout), tmpbuf, n);
  1131.     }
  1132. }
  1133. #endif    /*USE_MSGHDR*/
  1134.  
  1135.     close(sockfd);
  1136.     RETURNMAIN(ret);
  1137.  
  1138. doityourself:
  1139. #if    DEBUG
  1140.     printf("doing it myself :-(\n");
  1141. #endif    /*DEBUG*/
  1142. #endif    /*CLIENTSERVER*/
  1143.     setbuf(stdout, NULL);    /* Unbuffered I/O to always get every result */
  1144.     setbuf(stderr, NULL);
  1145.     glimpse_call = 0;
  1146.     glimpse_clientdied = 0;
  1147.     ret = process_query(oldargc, oldargv, fileno(stdin));
  1148.     RETURNMAIN(ret);
  1149. #endif    /*ISSERVER && CLIENTSERVER*/
  1150. }
  1151.  
  1152. process_query(argc, argv, newsockfd)
  1153. int argc; 
  1154. char *argv[];
  1155. int newsockfd;
  1156. {
  1157.     int    searchpercent;
  1158.     int    num_blocks;
  1159.     int    num_read;
  1160.     int    i, j;
  1161.     int    iii; /* Udi */
  1162.     int    jjj;
  1163.     char    c;
  1164.     char    *p;
  1165.     int    ret;
  1166.     int    jj;
  1167.     int    quitwhile;
  1168.     char    indexdir[MAX_LINE_LEN];
  1169.     char    TEMP_FILE[MAX_LINE_LEN];
  1170.     char    temp_file[MAX_LINE_LEN];
  1171.     int    oldargc = argc;
  1172.     char    **oldargv = argv;
  1173.     CHAR    dummypat[MAX_PAT];
  1174.     int    dummylen=0;
  1175.     int    my_M_index, my_P_index, my_b_index, my_A_index, my_l_index = -1, my_B_index = -1;
  1176.     char    **outname;
  1177.     int    gnum_of_matched = 0;
  1178.     int    gprev_num_of_matched = 0;
  1179.     int    gfiles_matched = 0;
  1180.     int    foundpat = 0;
  1181.     int    wholefilescope=0;
  1182.     int    nobytelevelmustbeon=0;
  1183.  
  1184.     if ((argc <= 0) || (argv == NULL)) {
  1185.         errno = EINVAL;
  1186.         return -1;
  1187.     }
  1188. /*
  1189.  * Macro to destroy EVERYTHING before return since we might want to make this a
  1190.  * library function later on: convention is that after destroy, objects are made
  1191.  * NULL throughout the source code, and are all set to NULL at initialization time.
  1192.  * DO agrep_argv, index_argv and FileOpt my_malloc/my_free optimizations later.
  1193.  * my_free calls have 2nd parameter = 0 if the size is not easily determinable.
  1194.  */
  1195. #define RETURN(val) \
  1196. {\
  1197.     int    q,k;\
  1198. \
  1199.     first_search = 0;\
  1200.     for (k=0; k<MAX_ARGS; k++) {\
  1201.         if (agrep_argv[k] != NULL) my_free(agrep_argv[k], 0);\
  1202.         if (index_argv[k] != NULL) my_free(index_argv[k], 0);\
  1203.         agrep_argv[k] = index_argv[k] = NULL;\
  1204.     }\
  1205.     if (FileOpt != NULL) my_free(FileOpt, MAXFILEOPT);\
  1206.     FileOpt = NULL;\
  1207.     for (k=0; k<MAXNUM_PAT; k++) {\
  1208.         if (pat_list[k] != NULL) my_free(pat_list[k], 0);\
  1209.         pat_list[k] = NULL;\
  1210.     }\
  1211.     sprintf(tempfile, "%s/.glimpse_tmp.%d", TEMP_DIR, getpid());\
  1212.     unlink(tempfile);\
  1213.     sprintf(outname[0], "%s/.glimpse_apply.%d", TEMP_DIR, getpid());\
  1214.     unlink(outname[0]);\
  1215.     my_free(outname[0], 0);\
  1216.     my_free(outname, 0);\
  1217. \
  1218.     if (ByteLevelIndex) {\
  1219.         if (src_offset_table != NULL) for (k=0; k<OneFilePerBlock; k++) {\
  1220.             free_list(&src_offset_table[k]);\
  1221.         }\
  1222.         /* Don't make src_offset_table itself NULL: it will be bzero-d below if !NULL */\
  1223.         for (q=0; q<MAXNUM_PAT; q++) {\
  1224.             if (multi_dest_offset_table[q] != NULL) for (k=0; k<OneFilePerBlock; k++) {\
  1225.             free_list(&multi_dest_offset_table[q][k]);\
  1226.             }\
  1227.             /* Don't make multi_dest_offset_table[q] itself NULL: it will be bzero-d below if !NULL */\
  1228.         }\
  1229.     }\
  1230.     for (k=0; k<num_terminals;k++)\
  1231.         free(terminals[k].data.leaf.value);\
  1232.     if (ComplexBoolean) destroy_tree(&GParse);\
  1233.     for (k=0; k<GNumfiles; k++) {\
  1234.         my_free(GTextfiles[k], 0);\
  1235.         GTextfiles[k] = NULL;\
  1236.     }\
  1237.     /* Don't free the GTextfiles buffer itself since it is allocated once in get_filename.c */\
  1238.     return (val);\
  1239. }
  1240.  
  1241.     /*
  1242.      * Initialize
  1243.      */
  1244.     strcpy(&GProgname[0], argv[0]);
  1245.     if (argc <= 1) return(usage());
  1246.     strcpy(TEMP_DIR, "/tmp");
  1247.     D_length = 0;
  1248.     D = 0;
  1249.     pattern_index = 0;
  1250.     first_search = 1;
  1251.     outname  = (char **)my_malloc(sizeof(char *));
  1252.     outname[0] = (char *)my_malloc(MAX_LINE_LEN);
  1253.     NOBYTELEVEL = 0;
  1254.     OPTIMIZEBYTELEVEL = 0;
  1255.     GLIMITOUTPUT = 0;
  1256.     GLIMITTOTALFILE = 0;
  1257.     GBESTMATCH = 0;
  1258.     GRECURSIVE = 0;
  1259.     GNOPROMPT = 0;
  1260.     GBYTECOUNT = 0;
  1261.     GPRINTFILENUMBER = 0;
  1262.     GOUTTAIL = 2;    /* stupid fix, but works */
  1263.     GFILENAMEONLY = 0;
  1264.     GNOFILENAME = 0;
  1265.     MATCHFILE = 0;
  1266.     PRINTATTR = 0;
  1267.     PRINTINDEXLINE = 0;
  1268.     Pat_as_is=0;
  1269.     Only_first = 0;
  1270.     PRINTAPPXFILEMATCH = 0;
  1271.     GCOUNT = 0;
  1272.     HINTSFROMUSER = 0;
  1273.     foundattr = 0;
  1274.     ComplexBoolean = 0;
  1275.     bestmatcherrors = 0;
  1276.     patbufpos = -1;
  1277.     RegionLimit=DEFAULT_REGION_LIMIT;
  1278.     strcpy(GD_pattern, "\n");
  1279.     GD_length = strlen(GD_pattern);
  1280.     indexdir[0] = '\0';
  1281.     memset(index_argv, '\0', sizeof(char *) * MAX_ARGS);
  1282.     index_argc = 0;
  1283.     memset(agrep_argv, '\0', sizeof(char *) * MAX_ARGS);
  1284.     agrep_argc = 0;
  1285.     FileOpt = NULL;
  1286.     fileopt_length = 0;
  1287.     memset(pat_list, '\0', sizeof(char *) * MAXNUM_PAT);
  1288.     memset(pat_attr, '\0', sizeof(int) * MAXNUM_PAT);
  1289.     for (i=0; i<MAX_ARGS; i++)
  1290.         index_argv[i] = (char *)my_malloc(MaxNameLength + 2);
  1291.     memset(is_mgrep_pat, '\0', sizeof(int) * MAXNUM_PAT);
  1292.     memset(mgrep_pat_index, '\0', sizeof(int) *MAXNUM_PAT);
  1293.     num_mgrep_pat = 0;
  1294.     memset(pat_buf, '\0', (MAXNUM_PAT + 2)*MAXPAT);
  1295.     pat_ptr = 0;
  1296.     sprintf(tempfile, "%s/.glimpse_tmp.%d", TEMP_DIR, getpid());
  1297.     /* Set WHOLEFILESCOPE for per-request processing at server */
  1298.     if (StructuredIndex) WHOLEFILESCOPE = 1;
  1299.     else WHOLEFILESCOPE = 0;
  1300.  
  1301.     if (argc > MAX_ARGS) {
  1302. #if    ISSERVER
  1303.     fprintf(stderr, "too many arguments %d obtained on server!\n", argc);
  1304. #endif    /*ISSERVER*/
  1305.         i = fileagrep(oldargc, oldargv, 0, stdout);
  1306.         RETURN(i);
  1307.     }
  1308.  
  1309.     /*
  1310.      * Process what options you can, then call fileagrep_init() to set
  1311.      * options in agrep and get the pattern. Then, call fileagrep_search().
  1312.      * Begin by copying options into agrep_argv assuming glimpse was not
  1313.      * called as agrep (optimistic :-).
  1314.      */
  1315.  
  1316.     agrep_argc = 0;
  1317.     for (i=0; i<MAX_ARGS; i++) agrep_argv[i] = NULL;
  1318.     agrep_argv[agrep_argc] = (char *)my_malloc(strlen(argv[0]) + 2);
  1319.     strcpy(agrep_argv[agrep_argc], argv[0]);    /* copy the name of the program anyway */
  1320.     agrep_argc ++;
  1321.  
  1322.     /* In glimpse, you should never output filenames with zero matches */
  1323.     if (agrep_argc + 1 >= MAX_ARGS) {
  1324.         fprintf(stderr, "%s: too many options!\n", GProgname);
  1325.         RETURN(usage());
  1326.     }
  1327.     agrep_argv[agrep_argc] = (char *)my_malloc(sizeof(char *));
  1328.     agrep_argv[agrep_argc][0] = '-';
  1329.     agrep_argv[agrep_argc][1] = 'z';
  1330.     agrep_argv[agrep_argc][2] = '\0';
  1331.     agrep_argc ++;
  1332.  
  1333.     /* In glimpse, you should always print pattern when using mgrep (user can't do -f or -m)! */
  1334.     if (agrep_argc + 1 >= MAX_ARGS) {
  1335.         fprintf(stderr, "%s: too many options!\n", GProgname);
  1336.         RETURN(usage());
  1337.     }
  1338.     agrep_argv[agrep_argc] = (char *)my_malloc(sizeof(char *));
  1339.     agrep_argv[agrep_argc][0] = '-';
  1340.     agrep_argv[agrep_argc][1] = 'P';
  1341.     agrep_argv[agrep_argc][2] = '\0';
  1342.     my_P_index = agrep_argc;
  1343.     agrep_argc ++;
  1344.  
  1345.     /* In glimpse, you should always output multiple when doing mgrep */
  1346.     if (agrep_argc + 1 >= MAX_ARGS) {
  1347.         fprintf(stderr, "%s: too many options!\n", GProgname);
  1348.         RETURN(usage());
  1349.     }
  1350.     agrep_argv[agrep_argc] = (char *)my_malloc(sizeof(char *));
  1351.     agrep_argv[agrep_argc][0] = '-';
  1352.     agrep_argv[agrep_argc][1] = 'M';
  1353.     agrep_argv[agrep_argc][2] = '\0';
  1354.     my_M_index = agrep_argc;
  1355.     agrep_argc ++;
  1356.  
  1357.     /* In glimpse, you should print the byte offset if there is a structured query */
  1358.     if (agrep_argc + 1 >= MAX_ARGS) {
  1359.         fprintf(stderr, "%s: too many options!\n", GProgname);
  1360.         RETURN(usage());
  1361.     }
  1362.     agrep_argv[agrep_argc] = (char *)my_malloc(sizeof(char *));
  1363.     agrep_argv[agrep_argc][0] = '-';
  1364.     agrep_argv[agrep_argc][1] = 'b';
  1365.     agrep_argv[agrep_argc][2] = '\0';
  1366.     my_b_index = agrep_argc;
  1367.     agrep_argc ++;
  1368.  
  1369.     /* In glimpse, you should always have space for doing -m if required */
  1370.     if (agrep_argc + 2 >= MAX_ARGS) {
  1371.         fprintf(stderr, "%s: too many options!\n", GProgname);
  1372.         RETURN(usage());
  1373.     }
  1374.     agrep_argv[agrep_argc] = (char *)my_malloc(sizeof(char *));
  1375.     agrep_argv[agrep_argc][0] = '-';
  1376.     agrep_argv[agrep_argc][1] = 'm';
  1377.     agrep_argv[agrep_argc][2] = '\0';
  1378.     agrep_argc ++;
  1379.     agrep_argv[agrep_argc] = (char *)my_malloc(2);    /* no op */
  1380.     agrep_argv[agrep_argc][0] = '\0';
  1381.     agrep_argc ++;
  1382.  
  1383.     /* Add -A option to print filenames as default */
  1384.     if (agrep_argc + 1 >= MAX_ARGS) {
  1385.         fprintf(stderr, "%s: too many options!\n", GProgname);
  1386.         RETURN(usage());
  1387.     }
  1388.     agrep_argv[agrep_argc] = (char *)my_malloc(sizeof(char *));
  1389.     agrep_argv[agrep_argc][0] = '-';
  1390.     agrep_argv[agrep_argc][1] = 'A';
  1391.     agrep_argv[agrep_argc][2] = '\0';
  1392.     my_A_index = agrep_argc;
  1393.     agrep_argc ++;
  1394.  
  1395.     while((agrep_argc < MAX_ARGS) && (--argc > 0) && (*++argv)[0] == '-' ) {
  1396.         p = argv[0] + 1;    /* ptr to first character after '-' */
  1397.         c = *(argv[0]+1);
  1398.         quitwhile = OFF;
  1399.         while (!quitwhile && (*p != '\0')) {
  1400.             c = *p;
  1401.             switch(c) {
  1402.             case 'F' : 
  1403.                 MATCHFILE = ON;
  1404.                 FileOpt = (CHAR *)my_malloc(MAXFILEOPT);
  1405.                 if (*(p + 1) == '\0') {/* space after - option */
  1406.                     if(argc <= 1) {
  1407.                         fprintf(stderr, "%s: a file pattern must follow the -F option\n", GProgname);
  1408.                         RETURN(usage());
  1409.                     }
  1410.                     argv++;
  1411.                     if ((dummylen = strlen(argv[0])) > MAXFILEOPT) {
  1412.                         fprintf(stderr, "%s: -F option list too long\n", GProgname);
  1413.                         RETURN(usage());
  1414.                     }
  1415.                     strcpy(FileOpt, argv[0]);
  1416.                     argc--;
  1417.                 } else {
  1418.                     if ((dummylen = strlen(p+1)) > MAXFILEOPT) {
  1419.                         fprintf(stderr, "%s: -F option list too long\n", GProgname);
  1420.                         RETURN(usage());
  1421.                     }
  1422.                     strcpy(FileOpt, p+1);
  1423.                 } /* else */
  1424.                 quitwhile = ON;
  1425.                 break;
  1426.  
  1427.             /*
  1428.              * indexed search - use the exact pattern to search the index as well:
  1429.              * not implemented yet
  1430.             case 'X' :
  1431.                 Pat_as_is = ON;
  1432.                 break;
  1433.              */
  1434.  
  1435.             /* search the index only and output the number of blocks */
  1436.             case 'N' :
  1437.                 Only_first = ON;
  1438.                 break ;
  1439.  
  1440.             /* also keep track of the matches in each file */
  1441.             case 'Q' :
  1442.                 PRINTAPPXFILEMATCH = ON;
  1443.                 break ;
  1444.  
  1445.             case 'U' :
  1446.                 HINTSFROMUSER = ON;
  1447.                 break;
  1448.  
  1449.             /* go to home directory to find the index: even if server overwrites indexdir here, it won't overwrite INDEX_DIR until read_index() */
  1450.             case 'H' :
  1451.                 if (*(p + 1) == '\0') {/* space after - option */
  1452.                     if (argc <= 1) {
  1453.                         fprintf(stderr, "%s: a directory name must follow the -H option\n", GProgname);
  1454.                         RETURN(usage());
  1455.                     }
  1456.                     argv ++;
  1457. #if    !ISSERVER
  1458.                     strcpy(indexdir, argv[0]);
  1459. #endif    /*!ISSERVER*/
  1460.                     argc --;
  1461.                 }
  1462. #if    !ISSERVER
  1463.                 else {
  1464.                     strcpy(indexdir, p+1);
  1465.                 }
  1466.                 agrep_argv[agrep_argc] = (char *)my_malloc(4);
  1467.                 strcpy(agrep_argv[agrep_argc], "-H");
  1468.                 agrep_argc ++;
  1469.                 agrep_argv[agrep_argc] = (char *)my_malloc(strlen(indexdir) + 2);
  1470.                 strcpy(agrep_argv[agrep_argc], indexdir);
  1471.                 agrep_argc ++;
  1472. #endif    /*!ISSERVER*/
  1473.                 quitwhile = ON;
  1474.                 break;
  1475.  
  1476. #if    ISSERVER && SFS_COMPAT
  1477.             /* INDEX_DIR will be already set since this is the server, so we can direclty xfer the .glimpse_* files */
  1478.             case '.' :
  1479.                 strcpy(TEMP_FILE, INDEX_DIR);
  1480.                 strcpy(temp_file, ".");
  1481.                 strcat(TEMP_FILE, "/.");
  1482.                 if (*(p + 1) == '\0') {/* space after - option */
  1483.                     if (argc <= 1) {
  1484.                         fprintf(stderr, "%s: a file name must follow the -. option\n", GProgname);
  1485.                         RETURN(usage());
  1486.                     }
  1487.                     argv ++;
  1488.                     strcat(TEMP_FILE, argv[0]);
  1489.                     strcat(temp_file, argv[0]);
  1490.                     argc --;
  1491.                 }
  1492.                 else {
  1493.                     strcat(TEMP_FILE, p+1);
  1494.                     strcat(temp_file, p+1);
  1495.                 }
  1496.                 if (!strcmp(temp_file, INDEX_FILE) || !strcmp(temp_file, FILTER_FILE) ||
  1497.                     !strcmp(temp_file, ATTRIBUTE_FILE) || !strcmp(temp_file, MINI_FILE) ||
  1498.                     !strcmp(temp_file, P_TABLE) || !strcmp(temp_file, PROHIBIT_LIST) ||
  1499.                     !strcmp(temp_file, INCLUDE_LIST) || !strcmp(temp_file, NAME_LIST) ||
  1500.                     !strcmp(temp_file, NAME_LIST_INDEX) || !strcmp(temp_file, NAME_HASH) ||
  1501.                     !strcmp(temp_file, NAME_HASH_INDEX) || !strcmp(temp_file, DEF_STAT_FILE) ||
  1502.                     !strcmp(temp_file, DEF_MESSAGE_FILE)) {
  1503.                     if ((ret = open(TEMP_FILE, O_RDONLY, 0)) <= 0) RETURN(ret);
  1504.                     while ((num_read = read(ret, matched_region, MAX_REGION_LIMIT*2)) > 0) {
  1505.                         write(1 /* NOT TO newsockfd since that was got by a syscall!!! */, matched_region, num_read);
  1506.                     }
  1507.                     close(ret);
  1508.                 }
  1509.                 quitwhile = ON;
  1510.                 RETURN(0);
  1511. #endif    /* ISSERVER */
  1512.  
  1513.             /* go to temp directory to create temp files */
  1514.             case 'T' :
  1515.                 if (*(p + 1) == '\0') {/* space after - option */
  1516.                     if (argc <= 1) {
  1517.                         fprintf(stderr, "%s: a directory name must follow the -T option\n", GProgname);
  1518.                         RETURN(usage());
  1519.                     }
  1520.                     argv ++;
  1521.                     strcpy(TEMP_DIR, argv[0]);
  1522.                     argc --;
  1523.                 }
  1524.                 else {
  1525.                     strcpy(TEMP_DIR, p+1);
  1526.                 }
  1527.                 sprintf(tempfile, "%s/.glimpse_tmp.%d", TEMP_DIR, getpid());
  1528.                 quitwhile = ON;
  1529.                 break;
  1530.  
  1531.             case 'R' :
  1532.                 if (*(p + 1) == '\0') {/* space after - option */
  1533.                     if (argc <= 1) {
  1534.                         fprintf(stderr, "%s: the record size must follow the -R option\n", GProgname);
  1535.                         RETURN(usage());
  1536.                     }
  1537.                     argv ++;
  1538.                     RegionLimit = atoi(argv[0]);
  1539.                     argc --;
  1540.                 }
  1541.                 else {
  1542.                     RegionLimit = atoi(p+1);
  1543.                 }
  1544.                 if ((RegionLimit <= 0) || (RegionLimit > MAX_REGION_LIMIT)) {
  1545.                     fprintf(stderr, "Bad record size %d: must be in [%d, %d]: using default %d\n",
  1546.                         RegionLimit, 1, MAX_REGION_LIMIT, DEFAULT_REGION_LIMIT);
  1547.                     RegionLimit = DEFAULT_REGION_LIMIT;
  1548.                 }
  1549.                 quitwhile = ON;
  1550.                 break;
  1551.  
  1552.             /* doesn't matter if we overwrite the value in the client since the same value would have been picked up in main() anyway */
  1553.             case 'J' :
  1554.                 if (*(p + 1) == '\0') {/* space after - option */
  1555.                     if (argc <= 1) {
  1556.                         fprintf(stderr, "%s: the server host name must follow the -J option\n", GProgname);
  1557.                         RETURNMAIN(usageS());
  1558.                     }
  1559.                     argv ++;
  1560. #if    !ISSERVER
  1561.                     strcpy(SERV_HOST, argv[0]);
  1562. #endif    /*!ISSERVER*/
  1563.                     argc --;
  1564.                 }
  1565. #if    !ISSERVER
  1566.                 else {
  1567.                     strcpy(SERV_HOST, p+1);
  1568.                 }
  1569. #endif    /*!ISSERVER*/
  1570.                 quitwhile = ON;
  1571.                 break;
  1572.  
  1573.             /* doesn't matter if we overwrite the value in the client since the same value would have been picked up in main() anyway */
  1574.             case 'K' :
  1575.                 if (*(p + 1) == '\0') {/* space after - option */
  1576.                     if (argc <= 1) {
  1577.                         fprintf(stderr, "%s: the server port must follow the -C option\n", GProgname);
  1578.                         RETURN(usage());
  1579.                     }
  1580.                     argv ++;
  1581. #if    !ISSERVER
  1582.                     SERV_PORT = atoi(argv[0]);
  1583. #endif    /*!ISSERVER*/
  1584.                     argc --;
  1585.                 }
  1586. #if    !ISSERVER
  1587.                 else {
  1588.                     SERV_PORT = atoi(p+1);
  1589.                 }
  1590.                 if ((SERV_PORT < MIN_SERV_PORT) || (SERV_PORT > MAX_SERV_PORT)) {
  1591.                     fprintf(stderr, "Bad server port %d: must be in [%d, %d]: using default %d\n",
  1592.                         SERV_PORT, MIN_SERV_PORT, MAX_SERV_PORT, DEF_SERV_PORT);
  1593.                     SERV_PORT = DEF_SERV_PORT;
  1594.                 }
  1595. #endif    /*!ISSERVER*/
  1596.                 quitwhile = ON;
  1597.                 break;
  1598.             
  1599.             case 'C' :
  1600.                 CONTACT_SERVER = 1;
  1601.                 break;
  1602.  
  1603.             case 'a' :
  1604.                 PRINTATTR = 1;
  1605.                 break;
  1606.  
  1607.             case 'E':
  1608.                 PRINTINDEXLINE = 1;
  1609.                 break;
  1610.  
  1611.             case 'W':
  1612.                 wholefilescope = 1;
  1613.                 break;
  1614.  
  1615.             case 'z' :
  1616.                 UseFilters = 1;
  1617.                 break;
  1618.  
  1619.             case 'r' :
  1620.                 GRECURSIVE = 1;
  1621.                 break;
  1622.  
  1623.             case 'V' :
  1624.                 printf("\nThis is glimpse version %s, %s.\n\n", GLIMPSE_VERSION, GLIMPSE_DATE);
  1625.                 RETURN(0);
  1626.  
  1627.             /* Must let 'f' and 'm' fall thru to default once multipatterns are done in agrep */
  1628.             case 'f' :
  1629.             case 'p' :
  1630.             case 'm' :
  1631.             case 'v' :
  1632.                 fprintf(stderr, "%s: illegal option: '-%c'\n", GProgname, c);
  1633.                 RETURN(usage());
  1634.  
  1635.             case 'I' :
  1636.             case 'D' :
  1637.             case 'S' :
  1638.                 /* There is no space after these options */
  1639.                 agrep_argv[agrep_argc] = (char *)my_malloc(strlen(argv[0]) + 2);
  1640.                 agrep_argv[agrep_argc][0] = '-';
  1641.                 strcpy(agrep_argv[agrep_argc] + 1, p);
  1642.                 agrep_argc ++;
  1643.                 quitwhile = ON;
  1644.                 break;
  1645.  
  1646.             case 'l':
  1647.                 GFILENAMEONLY = 1;
  1648.                 my_l_index = agrep_argc;
  1649.                 agrep_argv[agrep_argc] = (char *)my_malloc(4);
  1650.                 agrep_argv[agrep_argc][0] =  '-';
  1651.                 agrep_argv[agrep_argc][1] = c;
  1652.                 agrep_argv[agrep_argc][2] = '\0';
  1653.                 agrep_argc ++;
  1654.                 break;
  1655.  
  1656.             /*
  1657.              * Copy the set of options for agrep: put them in separate argvs
  1658.              * even if they are together after one '-' (easier to process).
  1659.              * These are agrep options which glimpse has to peek into.
  1660.              */
  1661.             default:
  1662.                 agrep_argv[agrep_argc] = (char *)my_malloc(16);
  1663.                 agrep_argv[agrep_argc][0] =  '-';
  1664.                 agrep_argv[agrep_argc][1] = c;
  1665.                 agrep_argv[agrep_argc][2] = '\0';
  1666.                 agrep_argc ++;
  1667.  
  1668.                 if (c == 'n') {
  1669.                     nobytelevelmustbeon=1;
  1670.                 }
  1671.                 else if (c == 'b') GBYTECOUNT = 1;
  1672.                 else if (c == 'g') GPRINTFILENUMBER = 1;
  1673.                 else if (c == 't') GOUTTAIL = 1;
  1674.                 else if (c == 'y') GNOPROMPT = 1;
  1675.                 else if (c == 'h') GNOFILENAME = 1;
  1676.                 else if (c == 'c') GCOUNT = 1;
  1677.                 else if (c == 'B') {
  1678.                     GBESTMATCH = 1;
  1679.                     my_B_index = agrep_argc - 1;
  1680.                 }
  1681.                 /* the following options are followed by a parameter */
  1682.                 else if ((c == 'e') || (c == 'd') || (c == 'L') || (c == 'k')) {
  1683.                     if (*(p + 1) == '\0') {/* space after - option */
  1684.                         if(argc <= 1) {
  1685.                             fprintf(stderr, "%s: the '-%c' option must have an argument\n", GProgname, c);
  1686.                             RETURN(usage());
  1687.                         }
  1688.                         argv++;
  1689.                         if ( (c == 'd') && ((D_length = strlen(argv[0])) > MAX_NAME_SIZE) ) {
  1690.                             fprintf(stderr, "%s: delimiter pattern too long (has > %d chars)\n", GProgname, MAX_NAME_SIZE);
  1691.                             RETURN(usage());
  1692.                             /* Should this be RegionLimit if ByteLevelIndex? */
  1693.                         }
  1694.                         else if (c == 'L') {
  1695.                             GLIMITOUTPUT = GLIMITTOTALFILE = GLIMITPERFILE = 0;
  1696.                             sscanf(argv[0], "%d:%d:%d", &GLIMITOUTPUT, &GLIMITTOTALFILE, &GLIMITPERFILE);
  1697.                             if ((GLIMITOUTPUT < 0) || (GLIMITTOTALFILE < 0) || (GLIMITPERFILE < 0)) {
  1698.                                 fprintf(stderr, "%s: invalid output limit %s\n", GProgname, argv[0]);
  1699.                                 RETURN(usage());
  1700.                             }
  1701.                         }
  1702.                         agrep_argv[agrep_argc] = (char *)my_malloc(strlen(argv[0]) + 2);
  1703.                         strcpy(agrep_argv[agrep_argc], argv[0]);
  1704.                         if (c == 'd') {
  1705.                             preprocess_delimiter(argv[0], D_length, GD_pattern, &GD_length);
  1706.                             if (GOUTTAIL == 2) GOUTTAIL = 0;
  1707.                             /* Should this be RegionLimit if ByteLevelIndex? */
  1708.                         }
  1709.                         argc--;
  1710.                     } else {
  1711.                         if ( (c == 'd') && ((D_length = strlen(p+1)) > MAX_NAME_SIZE) ) {
  1712.                             fprintf(stderr, "%s: delimiter pattern too long (has > %d chars)\n", GProgname, MAX_NAME_SIZE);
  1713.                             RETURN(usage());
  1714.                             /* Should this be RegionLimit if ByteLevelIndex? */
  1715.                         }
  1716.                         else if (c == 'L') {
  1717.                             GLIMITOUTPUT = GLIMITTOTALFILE = GLIMITPERFILE = 0;
  1718.                             sscanf(p+1, "%d:%d:%d", &GLIMITOUTPUT, &GLIMITTOTALFILE, &GLIMITPERFILE);
  1719.                             if ((GLIMITOUTPUT < 0) || (GLIMITTOTALFILE < 0) || (GLIMITPERFILE < 0)) {
  1720.                                 fprintf(stderr, "%s: invalid output limit %s\n", GProgname, p+1);
  1721.                                 RETURN(usage());
  1722.                             }
  1723.                         }
  1724.                         agrep_argv[agrep_argc] = (char *)my_malloc(strlen(p+1) + 2);
  1725.                         strcpy(agrep_argv[agrep_argc], p+1);
  1726.                         if (c == 'd') {
  1727.                             preprocess_delimiter(p+1, D_length-2, GD_pattern, &GD_length);
  1728.                             if (GOUTTAIL == 2) GOUTTAIL = 0;
  1729.                             /* Should this be RegionLimit if ByteLevelIndex? */
  1730.                         }
  1731.                     }
  1732.                     agrep_argc ++;
  1733. #if    DEBUG
  1734.                     fprintf(stderr, "%d = %s\n", agrep_argc, agrep_argv[agrep_argc - 1]);
  1735. #endif    /*DEBUG*/
  1736.                     quitwhile = ON;
  1737.                     if ((c == 'e') || (c == 'k')) foundpat = 1;
  1738.                 }
  1739.                 /* else it is something that glimpse doesn't know and agrep needs to look at */
  1740.  
  1741.                 break;    /* from default: */
  1742.  
  1743.             } /* switch(c) */
  1744.             p ++;
  1745.         }
  1746.     } /* while (--argc > 0 && (*++argv)[0] == '-') */
  1747.  
  1748. /* exitloop: */
  1749.  
  1750.     if ((GBESTMATCH == ON) && (MATCHFILE == ON) && (Only_first == ON))
  1751.         fprintf(stderr, "%s: Warning: the number of matches may be incorrect when -B is used with -F.\n", HARVEST_PREFIX);
  1752.  
  1753.     if (GOUTTAIL) GOUTTAIL = 1;
  1754.  
  1755.     if (GNOFILENAME) {
  1756.         agrep_argv[my_A_index][1] = 'Z';    /* ignore the -A option */
  1757.     }
  1758.  
  1759. #if    ISSERVER && SFS_COMPAT
  1760.     if (RemoteFiles) {    /* force -NQ so that won't start looking for files! */
  1761.         Only_first = ON;
  1762.         PRINTAPPXFILEMATCH = ON;
  1763.     }
  1764. #endif
  1765.  
  1766.     if (argc > 0) {
  1767.         /* copy the rest of the options the pattern and the filenames if any verbatim */
  1768.         for (i=0; i<argc; i++) {
  1769.             if (agrep_argc >= MAX_ARGS) break;
  1770.             agrep_argv[agrep_argc] = (char *)my_malloc(strlen(argv[0]) + 2);
  1771.             strcpy(agrep_argv[agrep_argc], argv[0]);
  1772.             agrep_argc ++;
  1773.             argv ++;
  1774.         }
  1775.         if (!foundpat) argc --;
  1776.     }
  1777.  
  1778. #if    0
  1779.     for (j=0; j<agrep_argc; j++) printf("agrep_argv[%d] = %s\n", j, agrep_argv[j]);
  1780.     printf("argc = %d\n", argc);
  1781. #endif    /*0*/
  1782.  
  1783.     /*
  1784.      * Now perform the search by first looking at the index
  1785.      * and obtaining the files to search; and then search
  1786.      * them and output the result. If argc > 0, glimpse
  1787.      * runs as agrep: otherwise, it searches index, etc.
  1788.      */
  1789.  
  1790.     if (argc <= 0) {
  1791.         glimpse_call = 1;
  1792.         /* Initialize some data structures, read the index */
  1793.         if (GRECURSIVE == 1) {
  1794.             fprintf(stderr, "illegal option: '-r'\n");
  1795.             RETURN(usage());
  1796.         }
  1797.         num_terminals = 0;
  1798.         GParse = NULL;
  1799.         memset(terminals, '\0', sizeof(ParseTree) * MAXNUM_PAT);
  1800. #if    !ISSERVER
  1801.         if (-1 == read_index(indexdir)) RETURN(-1);
  1802. #endif    /*!ISSERVER*/
  1803.  
  1804. /*
  1805. This handles the -n option with ByteLevelIndex: disabled as of now, else should go into file search...
  1806.         if (nobytelevelmustbeon && ByteLevelIndex) {
  1807.             fprintf(stderr, "Warning: -n option used with byte-level index: must SEARCH the files\n");
  1808.             NOBYTELEVEL=ON;
  1809.         }
  1810. */
  1811.  
  1812.         WHOLEFILESCOPE = (WHOLEFILESCOPE || wholefilescope);
  1813.  
  1814.         if (ByteLevelIndex) {
  1815.             /* Must zero them here in addition to index search so that RETURN macro runs correctly */
  1816.             if ((src_offset_table == NULL) &&
  1817.                 ((src_offset_table = (struct offsets **)my_malloc(sizeof(struct offsets *) * OneFilePerBlock)) == NULL)) exit(2);
  1818.             memset(src_offset_table, '\0', sizeof(struct offsets *) * OneFilePerBlock);
  1819.             for (i=0; i<MAXNUM_PAT; i++) {
  1820.                 if ((multi_dest_offset_table[i] == NULL) &&
  1821.                     ((multi_dest_offset_table[i] = (struct offsets **)my_malloc(sizeof(struct offsets *) * OneFilePerBlock)) == NULL)) exit(2);
  1822.                 memset(multi_dest_offset_table[i], '\0', sizeof(struct offsets *) * OneFilePerBlock);
  1823.             }
  1824.         }
  1825.         read_filters(INDEX_DIR, UseFilters);
  1826.  
  1827.         if (glimpse_clientdied) RETURN(0);
  1828.         /* Now initialize agrep, set the options and get the actual pattern into GPattern */
  1829.         if ((GM = fileagrep_init(agrep_argc, agrep_argv, MAXPAT, GPattern)) <= 0) {
  1830.             /* this printf need not be there: agrep prints messages if error */
  1831.             fprintf(stderr, "%s: error in options or arguments to `agrep'\n", HARVEST_PREFIX);
  1832.             RETURN(usage());
  1833.         }
  1834.         patindex = pattern_index;
  1835.         for (j=0; j<GM; j++) {
  1836.             if (GPattern[j] == '\\') j++;
  1837.             else if (test_indexable_char[GPattern[j]]) break;
  1838.         }
  1839.         if (j >= GM) {
  1840.             fprintf(stderr, "%s: pattern '%s' has no indexable characters: glimpse cannot search for it\n", HARVEST_PREFIX, GPattern);
  1841.             RETURN(-1);
  1842.         }
  1843.  
  1844.         /* Split GPattern into individual boolean terms */
  1845.         if (split_pattern(GPattern, GM, APattern, terminals, &num_terminals, &GParse, StructuredIndex) <= 0) RETURN(-1);
  1846. #if    BG_DEBUG
  1847.         fprintf(debug, "GPattern = %s, APattern = %s, num_terminals = %d\n", GPattern, APattern, num_terminals);
  1848. #endif    /*BG_DEBUG*/
  1849.         if (foundattr) WHOLEFILESCOPE = 1;    /* makes no sense to search attribute=value expressions without WHOLEFILESCOPE */
  1850.         else if (!ComplexBoolean && !PRINTATTR && !((long)GParse & AND_EXP)) WHOLEFILESCOPE = 0;    /* ORs can be done without WHOLEFILESCOPE */
  1851.         if (WHOLEFILESCOPE <= 0) agrep_argv[my_b_index][1] = 'Z';
  1852. /*
  1853.         if (!ComplexBoolean && ((long)GParse & AND_EXP) && (my_l_index != -1)) agrep_argv[my_l_index][1] = 'Z';
  1854. */
  1855.         if ((ComplexBoolean || ((long)GParse & AND_EXP)) && (my_l_index != -1)) agrep_argv[my_l_index][1] = 'Z';
  1856.  
  1857.         /* Now re-initialize agrep_argv with APattern instead of GPattern */
  1858.         my_free(agrep_argv[patindex], 0);
  1859.         AM=strlen(APattern);
  1860.         agrep_argv[patindex] = (char *)my_malloc(AM + 2);
  1861.         strcpy(agrep_argv[patindex], APattern);
  1862.  
  1863.         if (HINTSFROMUSER) {
  1864.             int    num=0, x, y, i, j;
  1865.             char    temp[MAX_NAME_SIZE+2];
  1866.             struct offsets *o, *tailo, *heado;
  1867.  
  1868.             while(1) {
  1869.                 if ((num = readline(newsockfd, dest_index_buf, REAL_INDEX_BUF)) <= 0) {
  1870.                     fprintf(stderr, "Input format error with -U option\n");
  1871.                     RETURN(-1);
  1872.                 }
  1873.                 dest_index_buf[num+1] = '\n';
  1874.                 if (!strncmp(dest_index_buf, "BEGIN", strlen("BEGIN"))) break;
  1875.             }
  1876.             sscanf(&dest_index_buf[strlen("BEGIN")], "%d%d%d", &bestmatcherrors, &NOBYTELEVEL, &OPTIMIZEBYTELEVEL);
  1877.             /* printf("BEGIN %d %d %d\n", bestmatcherrors, NOBYTELEVEL, OPTIMIZEBYTELEVEL);    */
  1878.             num = readline(newsockfd, dest_index_buf, REAL_INDEX_BUF);
  1879.             while (num > 0) {
  1880.                 dest_index_buf[num+1] = '\n';
  1881.                 if (!strncmp(dest_index_buf, "END", strlen("END"))) break;
  1882.                 i = j = 0;
  1883.                 while ((j<MAX_NAME_SIZE) && (dest_index_buf[i] != ' ') && (dest_index_buf[i] != '[') && (dest_index_buf[i] != '\n'))
  1884.                     temp[j++] = dest_index_buf[i++];
  1885.                 temp[j] = '\0';
  1886.                 x = atoi(temp);
  1887.                 GFileIndex[GNumfiles] = x;
  1888.                 if (x == file_num - 1) {
  1889.                     bigbuffer[bigbuffer_size] = '\0';
  1890.                     GTextfiles[GNumfiles++] = (CHAR *)strdup(GTextfilenames[x]);
  1891.                     bigbuffer[bigbuffer_size] = '\n';
  1892.                 }
  1893.                 else {
  1894.                     *(GTextfilenames[x+1] - 1) = '\0';
  1895.                     GTextfiles[GNumfiles++] = (CHAR *)strdup(GTextfilenames[x]);
  1896.                     *(GTextfilenames[x+1] - 1) = '\n';
  1897.                 }
  1898.                 /* printf("%d %s [", x, GTextfiles[GNumfiles-1]); */
  1899.                 src_index_set[block2index(x)] |= block2mask(x);
  1900.                 if (ByteLevelIndex && !NOBYTELEVEL) {
  1901.                     heado = tailo = NULL;
  1902.                 onemorey:
  1903.                     j = 0;
  1904.                     while ((j<MAX_NAME_SIZE) && ((dest_index_buf[i] == ' ') || (dest_index_buf[i] == '['))) i++;
  1905.                     while ((j<MAX_NAME_SIZE) && (dest_index_buf[i] != ' ') && (dest_index_buf[i] != '\n') && (dest_index_buf[i] != ']'))
  1906.                         temp[j++] = dest_index_buf[i++];
  1907.                     temp[j] = '\0';
  1908.                     y = atoi(temp);
  1909.                     /* printf(" %d", y); */
  1910.                     o = (struct offsets *)my_malloc(sizeof(struct offsets));
  1911.                     o->offset = y;
  1912.                     o->next = NULL;
  1913.                     o->sign = o->done = 0;
  1914.                     if (heado == NULL) {
  1915.                         heado = o;
  1916.                         tailo = o;
  1917.                     }
  1918.                     else {
  1919.                         tailo->next = o;
  1920.                         tailo = o;
  1921.                     }
  1922.                     if (dest_index_buf[i] == ' ') goto onemorey;
  1923.                     src_offset_table[x] = heado;
  1924.                 }
  1925.                 /* printf("]\n"); */
  1926.                 num = readline(newsockfd, dest_index_buf, REAL_INDEX_BUF);
  1927.             }
  1928.             goto search_files;
  1929.         }
  1930.  
  1931.         /*
  1932.          * Copy the agrep-options that are relevant to index search into
  1933.          * index_argv (see man-pages for which options are relevant).
  1934.          * Also, adjust patindex whenever options are skipped over.
  1935.          * NOTE: agrep_argv does NOT contain two options after one '-'.
  1936.          */
  1937.         index_argc = 0;
  1938.         for (j=0; j<agrep_argc; j++) {
  1939.             if (agrep_argv[j][0] == '-') {
  1940.                 if ((agrep_argv[j][1] == 'c') || (agrep_argv[j][1] == 'h') || (agrep_argv[j][1] == 'l') || (agrep_argv[j][1] == 'n') ||
  1941.                     (agrep_argv[j][1] == 's') || (agrep_argv[j][1] == 't') || (agrep_argv[j][1] == 'G') || (agrep_argv[j][1] == 'O') ||
  1942.                     (agrep_argv[j][1] == 'b') || (agrep_argv[j][1] == 'i') || (agrep_argv[j][1] == 'u') || (agrep_argv[j][1] == 'g') ||
  1943.                     (agrep_argv[j][1] == 'E') || (agrep_argv[j][1] == 'Z')) {
  1944.                     patindex --;
  1945.                     continue;
  1946.                 }
  1947.                 if ((agrep_argv[j][1] == 'd') || (agrep_argv[j][1] == 'L')) {    /* skip over the argument too */
  1948.                     j++;
  1949.                     patindex -= 2;
  1950.                     continue;
  1951.                 }
  1952.                 if ((agrep_argv[j][1] == 'e') || (agrep_argv[j][1] == 'm')) {
  1953.                     strcpy(index_argv[index_argc], agrep_argv[j]);
  1954.                     index_argc ++; j++;
  1955.                     strcpy(index_argv[index_argc], agrep_argv[j]);
  1956.                     if (agrep_argv[j-1][1] == 'm') patbufpos = index_argc;    /* where to put the patbuf if fast-boolean by mgrep() */
  1957.                     index_argc ++;
  1958.                 }
  1959.                 else {    /* No arguments: just copy THAT option: maybe, change some options */
  1960.                     strcpy(index_argv[index_argc], agrep_argv[j]);
  1961.                     if (agrep_argv[j][1] == 'A') index_argv[index_argc][1] = 'h';
  1962.                     else if (agrep_argv[j][1] == 'x') index_argv[index_argc][1] = 'w';
  1963.                     index_argc++;
  1964.                 }
  1965.             }
  1966.             else {    /* This is either the pattern itself or a filename */
  1967.                 strcpy(index_argv[index_argc], agrep_argv[j]);
  1968.                 index_argc++;
  1969.             }
  1970.         }
  1971.         sprintf(index_argv[index_argc], "%s", INDEX_FILE);
  1972.         index_argc ++;
  1973. #if    0
  1974.         for (j=0; j<index_argc; j++) printf("index_argv[%d] = %s\n", j, index_argv[j]);
  1975.         printf("patindex = %d\n", patindex);
  1976. #endif    /*0*/
  1977.  
  1978.         /* Search the index and process index-search-only options; Worry about file-pattern */
  1979.         ret = search_index(GParse);
  1980.         if (ret <= 0) RETURN(-1);
  1981.         num_blocks=0;
  1982.         if (OneFilePerBlock) {
  1983.             for(iii=0; iii<round(OneFilePerBlock, 8*sizeof(int)); iii++) {
  1984.                 if (src_index_set[iii] == 0) continue;
  1985.                 for (jjj=0; jjj < 8*sizeof(int); jjj++)
  1986.                     if (src_index_set[iii] & mask_int[jjj])
  1987.                         num_blocks ++;
  1988.             }
  1989.             if (num_blocks > OneFilePerBlock) num_blocks = OneFilePerBlock;    /* roundoff */
  1990.         }
  1991.         else {
  1992.             for (iii=0; iii<MAX_PARTITION; iii++)
  1993.                 if (src_index_set[iii]) num_blocks++;
  1994.         }
  1995.         if (num_blocks <= 0) RETURN (0);
  1996.         if ((src_index_set[REAL_PARTITION - 1] == 1) && !Only_first && !OPTIMIZEBYTELEVEL) {
  1997.             fprintf(stderr, "Warning: pattern has words present in the stop-list: must SEARCH the files\n");
  1998.         }
  1999.         /* if just the NOBYTELEVEL flag is set, then it is an optimization which glimpse does and user need not be warned */
  2000. #if    DEBUG
  2001.         fprintf(stderr, "--> search=%d optimize=%d times=%d all=%d blocks=%d len=%d pat=%s scope=%d\n",
  2002.             NOBYTELEVEL, OPTIMIZEBYTELEVEL, src_index_set[REAL_PARTITION - 2], src_index_set[REAL_PARTITION - 1], num_blocks, strlen(APattern), APattern, WHOLEFILESCOPE);
  2003. #endif    /*DEBUG*/
  2004.         dummypat[0] = '\0';
  2005.         if (!MATCHFILE)    {    /* the argc,argv don't matter */
  2006.             get_filenames(src_index_set, 0, NULL, dummylen, dummypat, file_num);
  2007.  
  2008.             if (Only_first) { /* search the index only */
  2009.                 fprintf(stderr, "There are matches to %d out of %d %s\n", num_blocks, (OneFilePerBlock > 0) ? OneFilePerBlock : GNumpartitions, (OneFilePerBlock > 0) ? "files" : "blocks");
  2010.                 if (num_blocks > 0) {
  2011.                     char    cc[8];
  2012.                     cc[0] = 'y';
  2013. #if    !ISSERVER
  2014.                     if (!GNOPROMPT) {
  2015.                         fprintf(stderr, "Do you want to see the file names? (y/n)");
  2016.                         fgets(cc, 4, stdin);
  2017.                     }
  2018. #endif    /*!ISSERVER*/
  2019.                     if (cc[0] == 'y') {
  2020.                         if (PRINTAPPXFILEMATCH && Only_first && GPRINTFILENUMBER) {
  2021.                             printf("BEGIN %d %d %d\n", bestmatcherrors, NOBYTELEVEL, OPTIMIZEBYTELEVEL);
  2022.                         }
  2023.                         for (jjj=0; jjj<GNumfiles; jjj++) {
  2024.                             if (GPRINTFILENUMBER) printf("%d", GFileIndex[jjj]);
  2025.                             else printf("%s", GTextfiles[jjj]);
  2026.                             if (PRINTAPPXFILEMATCH) {
  2027.                                 if (GCOUNT) {
  2028.                                 int n = 0;
  2029.                                 printf(": ");
  2030.                                 if (ByteLevelIndex && (src_offset_table != NULL)) {
  2031.                                     struct offsets  *p1 = src_offset_table[GFileIndex[jjj]];
  2032.                                     while (p1 != NULL) {
  2033.                                         n ++;
  2034.                                         p1 = p1->next;
  2035.                                     }
  2036.                                 }
  2037.                                 else n = 1;    /* there is atleast 1 match */
  2038.                                 printf("%d", n);
  2039.                                 }
  2040.                                 else {
  2041.                                 printf(" [");
  2042.                                 if (ByteLevelIndex && (src_offset_table != NULL)) {
  2043.                                     struct offsets  *p1 = src_offset_table[GFileIndex[jjj]];
  2044.                                     while (p1 != NULL) {
  2045.                                         printf(" %d", p1->offset);
  2046.                                         p1 = p1->next;
  2047.                                     }
  2048.                                 }
  2049.                                 printf("]");
  2050.                                 }
  2051.                             }
  2052.                             printf("\n");
  2053.                         }
  2054.                         if (PRINTAPPXFILEMATCH && Only_first && GPRINTFILENUMBER) {
  2055.                             printf("END\n");
  2056.                         }
  2057.                     }
  2058.                 }
  2059.                 RETURN(0);
  2060.             }
  2061.             if (!OneFilePerBlock) searchpercent = num_blocks*100/GNumpartitions;
  2062.             else searchpercent = num_blocks * 100 / OneFilePerBlock;
  2063. #if    BG_DEBUG
  2064.             fprintf(debug, "searchpercent = %d, num_blocks = %d\n", searchpercent, num_blocks);
  2065. #endif    /*BG_DEBUG*/
  2066. #if    !ISSERVER
  2067.             if (!GNOPROMPT && (searchpercent > MAX_SEARCH_PERCENT)) {
  2068.                 char    cc[8];
  2069.                 cc[0] = 'y';
  2070.                 fprintf(stderr, "Your query may search about %d%% of the total space! Continue? (y/n)", searchpercent); 
  2071.                 fgets(cc, 4, stdin);
  2072.                 if (cc[0] != 'y') RETURN(0);
  2073.             }
  2074.             if (ByteLevelIndex && (searchpercent > DEF_MAX_INDEX_PERCENT)) NOBYTELEVEL = 1;
  2075. #endif    /*!ISSERVER*/
  2076.         }
  2077.         else {    /* set up the right options for -F in index_argv/index_argc itself since they will no longer be used */
  2078.             index_argc=0;
  2079.             strcpy(index_argv[0], GProgname);
  2080.  
  2081.             /* adding the -h option, which is safer for -F */
  2082.             index_argc ++;
  2083.             index_argv[index_argc][0] =  '-';
  2084.             index_argv[index_argc][1] = 'h';
  2085.             index_argv[index_argc][2] = '\0';
  2086.             index_argc ++;
  2087.  
  2088.             /* new code: bgopal, Feb/8/94: deleted udi's code here */
  2089.             j = 0;
  2090.             while (FileOpt[j] == '-') {
  2091.                 j++;
  2092.                 while ((FileOpt[j] != ' ') && (FileOpt[j] != '\0') && (FileOpt[j] != '\n')) {
  2093.                     if (j >= MAX_ARGS - 1) {
  2094.                         fprintf(stderr, "%s: too many options after -F: %s\n", GProgname, FileOpt);
  2095.                         RETURN(usage());
  2096.                     }
  2097.                     index_argv[index_argc][0] =  '-';
  2098.                     index_argv[index_argc][1] = FileOpt[j];
  2099.                     index_argv[index_argc][2] = '\0';
  2100.                     index_argc ++;
  2101.                     j++;
  2102.                 }
  2103.                 if ((FileOpt[j] == '\0') || (FileOpt[j] == '\n')) break;
  2104.                 if ((FileOpt[j] == ' ') && (FileOpt[j-1] == '-')) {
  2105.                     fprintf(stderr, "%s: illegal option: '-' after -F\n", GProgname);
  2106.                     RETURN(usage());
  2107.                 }
  2108.                 else if (FileOpt[j] == ' ') while(FileOpt[j] == ' ') j++;
  2109.             }
  2110.             while(FileOpt[j] == ' ') j++;
  2111.  
  2112.             fileopt_length = strlen(FileOpt);
  2113.             strncpy(index_argv[index_argc],FileOpt+j,fileopt_length-j);
  2114.             index_argv[index_argc][fileopt_length-j] = '\0';
  2115.             index_argc++;
  2116.             my_free(FileOpt, MAXFILEOPT);
  2117.             FileOpt = NULL;
  2118.  
  2119. #if    BG_DEBUG
  2120.             fprintf(debug, "pattern to check with -F = %s\n",index_argv[index_argc-1]);
  2121. #endif    /*BG_DEBUG*/
  2122. #if    DEBUG
  2123.             fprintf(stderr, "-F : ");
  2124.             for (jj=0; jj < index_argc; jj++) 
  2125.                 fprintf(stderr, " %s ",index_argv[jj]);
  2126.             fprintf(stderr, "\n");
  2127. #endif    /*DEBUG*/
  2128.             fflush(stdout);
  2129.             get_filenames(src_index_set, index_argc, index_argv, dummylen, dummypat, file_num);
  2130.  
  2131.             /* Assume #files per partitions is appx constant */
  2132.             if (OneFilePerBlock) num_blocks = GNumfiles;
  2133.             else num_blocks = GNumfiles * GNumpartitions / p_table[GNumpartitions - 1];
  2134.             if (Only_first) { /* search the index only */
  2135.                 fprintf(stderr, "There are matches to %d out of %d %s\n", num_blocks, (OneFilePerBlock > 0) ? OneFilePerBlock : GNumpartitions, (OneFilePerBlock > 0) ? "files" : "blocks");
  2136.                 if (num_blocks > 0) {
  2137.                     char    cc[8];
  2138.                     cc[0] = 'y';
  2139. #if    !ISSERVER
  2140.                     if (!GNOPROMPT) {
  2141.                         fprintf(stderr, "Do you want to see the file names? (y/n)");
  2142.                         fgets(cc, 4, stdin);
  2143.                     }
  2144. #endif    /*!ISSERVER*/
  2145.                     if (cc[0] == 'y') {
  2146.                         if (PRINTAPPXFILEMATCH && Only_first && GPRINTFILENUMBER) {
  2147.                             printf("BEGIN %d %d %d\n", bestmatcherrors, NOBYTELEVEL, OPTIMIZEBYTELEVEL);
  2148.                         }
  2149.                         for (jjj=0; jjj<GNumfiles; jjj++) {
  2150.                             if (GPRINTFILENUMBER) printf("%d", GFileIndex[jjj]);
  2151.                             else printf("%s", GTextfiles[jjj]);
  2152.                             if (PRINTAPPXFILEMATCH) {
  2153.                                 if (GCOUNT) {
  2154.                                 int n = 0;
  2155.                                 printf(": ");
  2156.                                 if (ByteLevelIndex && (src_offset_table != NULL)) {
  2157.                                     struct offsets  *p1 = src_offset_table[GFileIndex[jjj]];
  2158.                                     while (p1 != NULL) {
  2159.                                         n ++;
  2160.                                         p1 = p1->next;
  2161.                                     }
  2162.                                 }
  2163.                                 else n = 1;    /* there is atleast 1 match */
  2164.                                 printf("%d", n);
  2165.                                 }
  2166.                                 else {
  2167.                                 printf("[");
  2168.                                 if (ByteLevelIndex && (src_offset_table != NULL)) {
  2169.                                     struct offsets  *p1 = src_offset_table[GFileIndex[jjj]];
  2170.                                     while (p1 != NULL) {
  2171.                                         printf(" %d", p1->offset);
  2172.                                         p1 = p1->next;
  2173.                                     }
  2174.                                 }
  2175.                                 printf("]");
  2176.                                 }
  2177.                             }
  2178.                             printf("\n");
  2179.                         }
  2180.                         if (PRINTAPPXFILEMATCH && Only_first && GPRINTFILENUMBER) {
  2181.                             printf("END\n");
  2182.                         }
  2183.                     }
  2184.                 }
  2185.                 RETURN(0);
  2186.             }
  2187.             if (OneFilePerBlock) searchpercent = GNumfiles * 100 / OneFilePerBlock;
  2188.             else searchpercent = GNumfiles * 100 / p_table[GNumpartitions - 1];
  2189. #if    BG_DEBUG
  2190.             fprintf(debug, "searchpercent = %d, num_files = %d\n", searchpercent, p_table[GNumpartitions - 1]);
  2191. #endif    /*BG_DEBUG*/
  2192. #if    !ISSERVER
  2193.             if (!GNOPROMPT && (searchpercent > MAX_SEARCH_PERCENT)) {
  2194.                 char    cc[8];
  2195.                 cc[0] = 'y';
  2196.                 fprintf(stderr, "Your query may search about %d%% of the total space! Continue? (y/n)", searchpercent); 
  2197.                 fgets(cc, 4, stdin);
  2198.                 if (cc[0] != 'y') RETURN(0);
  2199.             }
  2200.             if (ByteLevelIndex && (searchpercent > DEF_MAX_INDEX_PERCENT)) NOBYTELEVEL = 1;
  2201. #endif    /*!ISSERVER*/
  2202.         }
  2203.  
  2204.     search_files:
  2205.         /* Replace -B by the number of errors if best-match */
  2206.         if (GBESTMATCH && (my_B_index >= 0)) {
  2207.             sprintf(&agrep_argv[my_B_index][1], "%d", bestmatcherrors);
  2208. #if    BG_DEBUG
  2209.             fprintf(debug, "Changing -B to -%d\n", bestmatcherrors);
  2210. #endif    /*BG_DEBUG*/
  2211.         }
  2212.         agrep_argv[my_M_index][1] = 'Z';
  2213.         agrep_argv[my_P_index][1] = 'Z';
  2214. /*
  2215.         if (!ComplexBoolean && ((long)GParse & AND_EXP) && (my_l_index != -1) && !WHOLEFILESCOPE) agrep_argv[my_l_index][1] = 'l';
  2216. */
  2217.         if ((ComplexBoolean || ((long)GParse & AND_EXP)) && (my_l_index != -1) && !WHOLEFILESCOPE) agrep_argv[my_l_index][1] = 'l';
  2218.  
  2219.         if (GNumfiles <= 0) RETURN(0);
  2220.         if (glimpse_clientdied) RETURN(0);
  2221.         /* must reinitialize since the above agrep calls for index-search ruined the real options: it is required EVEN IF ByteLevelIndex */
  2222.         AM = fileagrep_init(agrep_argc, agrep_argv, MAXPAT, APattern);
  2223.         /* do acutal search with postfiltering if structured query */
  2224.         if (WHOLEFILESCOPE <= 0) {
  2225.             if (!UseFilters) {
  2226.                 if (!ByteLevelIndex || NOBYTELEVEL) {
  2227.                     for (i=0; i<GNumfiles; i++) {
  2228.                         gprev_num_of_matched = gnum_of_matched;
  2229.                         SetCurrentFileName = 1;
  2230.                         if (GPRINTFILENUMBER) sprintf(CurrentFileName, "%d", GFileIndex[i]);
  2231.                         else strcpy(CurrentFileName, GTextfiles[i]);
  2232.                         if ((ret = fileagrep_search(AM, APattern, 1, >extfiles[i], 0, stdout)) > 0) {
  2233.                             gnum_of_matched += ret;
  2234.                             gfiles_matched ++;
  2235.                         }
  2236.                         SetCurrentFileName = 0;
  2237.                         if (GLIMITOUTPUT > 0) {
  2238.                             if (GLIMITOUTPUT <= gnum_of_matched) break;
  2239.                             LIMITOUTPUT = GLIMITOUTPUT - gnum_of_matched;
  2240.                         }
  2241.                         if (GLIMITTOTALFILE > 0) {
  2242.                             if (GLIMITTOTALFILE <= gfiles_matched) break;
  2243.                             LIMITTOTALFILE = GLIMITTOTALFILE - gfiles_matched;
  2244.                         }
  2245.                          if ((ret < 0) && (errno == AGREP_ERROR)) break;
  2246.                         if (glimpse_clientdied) break;
  2247.                         fflush(stdout);
  2248.                     }
  2249.                 }
  2250.                 else {
  2251.                     for (i=0; i<GNumfiles; i++) {
  2252.                         gprev_num_of_matched = gnum_of_matched;
  2253.                         SetCurrentFileName = 1;
  2254.                         if (GPRINTFILENUMBER) sprintf(CurrentFileName, "%d", GFileIndex[i]);
  2255.                         else strcpy(CurrentFileName, GTextfiles[i]);
  2256.                         if (stat(GTextfiles[i], &file_stat_buf) == -1) continue;
  2257.                         if (file_stat_buf.st_mtime > index_stat_buf.st_mtime) {
  2258.                             /* fprintf(stderr, "Warning: file modified after indexing: must SEARCH %s\n", CurrentFileName); */
  2259.                             free_list(&src_offset_table[GFileIndex[i]]);
  2260.                             first_search = 1;
  2261.                             if ((ret = fileagrep_search(AM, APattern, 1, >extfiles[i], 0, stdout)) > 0) {
  2262.                                 gnum_of_matched += ret;
  2263.                                 gfiles_matched ++;
  2264.                             }
  2265.                         }
  2266.                         else if ((ret = glimpse_search(AM, APattern, GD_length, GD_pattern, GTextfiles[i], GTextfiles[i], GFileIndex[i], src_offset_table, stdout)) > 0) {
  2267.                             gnum_of_matched += ret;
  2268.                             gfiles_matched ++;
  2269.                         }
  2270.                         SetCurrentFileName = 0;
  2271.                         if (GLIMITOUTPUT > 0) {
  2272.                             if (GLIMITOUTPUT <= gnum_of_matched) break;
  2273.                             LIMITOUTPUT = GLIMITOUTPUT - gnum_of_matched;
  2274.                         }
  2275.                         if (GLIMITTOTALFILE > 0) {
  2276.                             if (GLIMITTOTALFILE <= gfiles_matched) break;
  2277.                             LIMITTOTALFILE = GLIMITTOTALFILE - gfiles_matched;
  2278.                         }
  2279.                          if ((ret < 0) && (errno == AGREP_ERROR)) break;
  2280.                         if (glimpse_clientdied) break;
  2281.                         fflush(stdout);
  2282.                     }
  2283.                 }
  2284.             }
  2285.             else {
  2286.                 sprintf(outname[0], "%s/.glimpse_apply.%d", TEMP_DIR, getpid());
  2287.                 for (i=0; i<GNumfiles; i++) {
  2288.                     if (apply_filter(GTextfiles[i], outname[0]) == 1) {
  2289.                         gprev_num_of_matched = gnum_of_matched;
  2290.                         SetCurrentFileName = 1;
  2291.                         if (GPRINTFILENUMBER) sprintf(CurrentFileName, "%d", GFileIndex[i]);
  2292.                         else strcpy(CurrentFileName, GTextfiles[i]);
  2293.                         if (stat(GTextfiles[i], &file_stat_buf) == -1) continue;
  2294.                         if (!ByteLevelIndex || NOBYTELEVEL || (file_stat_buf.st_mtime > index_stat_buf.st_mtime)) {
  2295.                             first_search = 1;
  2296.                             if ((ret = fileagrep_search(AM, APattern, 1, outname, 0, stdout)) > 0) {
  2297.                                 gnum_of_matched += ret;
  2298.                                 gfiles_matched ++;
  2299.                             }
  2300.                         }
  2301.                         else {
  2302.                             if (file_stat_buf.st_mtime > index_stat_buf.st_mtime) {
  2303.                                 /* fprintf(stderr, "Warning: file modified after indexing: must SEARCH %s\n", CurrentFileName); */
  2304.                                 free_list(&src_offset_table[GFileIndex[i]]);
  2305.                                 first_search = 1;
  2306.                                 if ((ret = fileagrep_search(AM, APattern, 1, outname, 0, stdout)) > 0) {
  2307.                                     gnum_of_matched += ret;
  2308.                                     gfiles_matched ++;
  2309.                                 }
  2310.                             }
  2311.                             else if ((ret = glimpse_search(AM, APattern, GD_length, GD_pattern, GTextfiles[i], outname[0], GFileIndex[i], src_offset_table, stdout)) > 0) {
  2312.                                 gfiles_matched ++;
  2313.                                 gnum_of_matched += ret;
  2314.                             }
  2315.                         }
  2316.                         unlink(outname[0]);
  2317.                         SetCurrentFileName = 0;
  2318.                     }
  2319.                     else {
  2320.                         if (!ByteLevelIndex || NOBYTELEVEL) {
  2321.                             first_search = 1;
  2322.                             if ((ret = fileagrep_search(AM, APattern, 1, >extfiles[i], 0, stdout)) > 0) {
  2323.                                 gnum_of_matched += ret;
  2324.                                 gfiles_matched ++;
  2325.                             }
  2326.                         }
  2327.                         else {
  2328.                             SetCurrentFileName = 1;
  2329.                             if (GPRINTFILENUMBER) sprintf(CurrentFileName, "%d", GFileIndex[i]);
  2330.                             else strcpy(CurrentFileName, GTextfiles[i]);
  2331.                             if (stat(GTextfiles[i], &file_stat_buf) == -1) continue;
  2332.                             if (file_stat_buf.st_mtime > index_stat_buf.st_mtime) {
  2333.                                 /* fprintf(stderr, "Warning: file modified after indexing: must SEARCH %s\n", CurrentFileName); */
  2334.                                 free_list(&src_offset_table[GFileIndex[i]]);
  2335.                                 first_search = 1;
  2336.                                 if ((ret = fileagrep_search(AM, APattern, 1, >extfiles[i], 0, stdout)) > 0) {
  2337.                                     gnum_of_matched += ret;
  2338.                                     gfiles_matched ++;
  2339.                                 }
  2340.                             }
  2341.                             else if ((ret = glimpse_search(AM, APattern, GD_length, GD_pattern, GTextfiles[i], GTextfiles[i], GFileIndex[i], src_offset_table, stdout)) > 0) {
  2342.                                 gnum_of_matched += ret;
  2343.                                 gfiles_matched ++;
  2344.                             }
  2345.                             SetCurrentFileName = 0;
  2346.                         }
  2347.                     }
  2348.                     if (GLIMITOUTPUT > 0) {
  2349.                         if (GLIMITOUTPUT <= gnum_of_matched) break;
  2350.                         LIMITOUTPUT = GLIMITOUTPUT - gnum_of_matched;
  2351.                     }
  2352.                     if (GLIMITTOTALFILE > 0) {
  2353.                         if (GLIMITTOTALFILE <= gfiles_matched) break;
  2354.                         LIMITTOTALFILE = GLIMITTOTALFILE - gfiles_matched;
  2355.                     }
  2356.                      if ((ret < 0) && (errno == AGREP_ERROR)) break;
  2357.                     if (glimpse_clientdied) break;
  2358.                     fflush(stdout);
  2359.                 }
  2360.             }
  2361.         }
  2362.         else {
  2363.             FILE    *tmpfp = NULL;    /* to store structured query-search output */
  2364.             int     OLDLIMITOUTPUT; /* don't use LIMITs for search: only for filtering=identify_region(): agrep NEVER changes these 3 */
  2365.             int    OLDLIMITPERFILE;
  2366.             int    OLDLIMITTOTALFILE;
  2367.             int    OLDPRINTRECORD;    /* don't use PRINTRECORD for search: only after filter_output() recognizes boolean in wholefilescope */
  2368.             int    OLDCOUNT;    /* don't use OLDCOUNT for search: only after filter_output() recognizes boolean in wholefilescope */
  2369.  
  2370.             if (!UseFilters) {
  2371.                 for (i=0; i<GNumfiles; i++) {
  2372.                     OLDLIMITOUTPUT = LIMITOUTPUT;
  2373.                     LIMITOUTPUT = 0;
  2374.                     OLDLIMITPERFILE = LIMITPERFILE;
  2375.                     LIMITPERFILE = 0;
  2376.                     OLDLIMITTOTALFILE = LIMITTOTALFILE;
  2377.                     LIMITTOTALFILE = 0;
  2378.                     OLDPRINTRECORD = PRINTRECORD;
  2379.                     PRINTRECORD = 1;
  2380.                     OLDCOUNT = COUNT;
  2381.                     COUNT = 0;
  2382.                     gprev_num_of_matched = gnum_of_matched;
  2383.                     if ((tmpfp = fopen(tempfile, "w")) == NULL) {
  2384.                         fprintf(stderr, "%s: cannot open for writing: %s, errno=%d\n", GProgname, tempfile, errno);
  2385.                         RETURN(usage());
  2386.                     }
  2387.                     SetCurrentFileName = 1;
  2388.                     if (GPRINTFILENUMBER) sprintf(CurrentFileName, "%d", GFileIndex[i]);
  2389.                     else strcpy(CurrentFileName, GTextfiles[i]);
  2390.                     if (!ByteLevelIndex || NOBYTELEVEL) {
  2391.                         first_search = 1;
  2392.                         ret = fileagrep_search(AM, APattern, 1, >extfiles[i], 0, tmpfp);
  2393.                     }
  2394.                     else {
  2395.                         if (stat(GTextfiles[i], &file_stat_buf) == -1) {
  2396.                             fclose(tmpfp);
  2397.                             continue;
  2398.                         }
  2399.                         if (file_stat_buf.st_mtime > index_stat_buf.st_mtime) {
  2400.                             /* fprintf(stderr, "Warning: file modified after indexing: must SEARCH %s\n", CurrentFileName); */
  2401.                             free_list(&src_offset_table[GFileIndex[i]]);
  2402.                             first_search = 1;
  2403.                             ret = fileagrep_search(AM, APattern, 1, >extfiles[i], 0, tmpfp);
  2404.                         }
  2405.                         else ret = glimpse_search(AM, APattern, GD_length, GD_pattern, GTextfiles[i], GTextfiles[i], GFileIndex[i], src_offset_table, tmpfp);
  2406.                     }
  2407.                     SetCurrentFileName = 0;
  2408.                     fflush(tmpfp);
  2409.                     fclose(tmpfp);
  2410.                     tmpfp = NULL;
  2411.                     if ((ret < 0) && (errno == AGREP_ERROR)) break;
  2412. #if    DEBUG
  2413.                     printf("done search\n");
  2414.                     fflush(stdout);
  2415. #endif    /*DEBUG*/
  2416.                     LIMITOUTPUT = OLDLIMITOUTPUT;
  2417.                     LIMITPERFILE = OLDLIMITPERFILE;
  2418.                     LIMITTOTALFILE = OLDLIMITTOTALFILE;
  2419.                     PRINTRECORD = OLDPRINTRECORD;
  2420.                     COUNT = OLDCOUNT;
  2421.                     ret = filter_output(GTextfiles[i], tempfile, GParse, GD_pattern, GD_length, GOUTTAIL, nullfp, StructuredIndex);
  2422.                     gnum_of_matched += (ret > 0) ? ret : 0;
  2423.                     gfiles_matched += (ret > 0) ? 1 : 0;
  2424.                     if (GLIMITOUTPUT > 0) {
  2425.                         if (GLIMITOUTPUT <= gnum_of_matched) break;
  2426.                         LIMITOUTPUT = GLIMITOUTPUT - gnum_of_matched;
  2427.                     }
  2428.                     if (GLIMITTOTALFILE > 0) {
  2429.                         if (GLIMITTOTALFILE <= gfiles_matched) break;
  2430.                         LIMITTOTALFILE = GLIMITTOTALFILE - gfiles_matched;
  2431.                     }
  2432.                     if (glimpse_clientdied) break;
  2433.                     fflush(stdout);
  2434.                 }
  2435.             }
  2436.             else {    /* we should try to apply the filter (we come here with -W -z, say) */
  2437.                 sprintf(outname[0], "%s/.glimpse_apply.%d", TEMP_DIR, getpid());
  2438.                 for (i=0; i<GNumfiles; i++) {
  2439.                     OLDLIMITOUTPUT = LIMITOUTPUT;
  2440.                     LIMITOUTPUT = 0;
  2441.                     OLDLIMITPERFILE = LIMITPERFILE;
  2442.                     LIMITPERFILE = 0;
  2443.                     OLDLIMITTOTALFILE = LIMITTOTALFILE;
  2444.                     LIMITTOTALFILE = 0;
  2445.                     OLDPRINTRECORD = PRINTRECORD;
  2446.                     PRINTRECORD = 1;
  2447.                     OLDCOUNT = COUNT;
  2448.                     COUNT = 0;
  2449.                     gprev_num_of_matched = gnum_of_matched;
  2450.                     if ((tmpfp = fopen(tempfile, "w")) == NULL) {
  2451.                         fprintf(stderr, "%s: cannot open for writing: %s, errno=%d\n", GProgname, tempfile, errno);
  2452.                         RETURN(usage());
  2453.                     }
  2454.  
  2455.                     SetCurrentFileName = 1;
  2456.                     if (GPRINTFILENUMBER) sprintf(CurrentFileName, "%d", GFileIndex[i]);
  2457.                     else strcpy(CurrentFileName, GTextfiles[i]);
  2458.                     if (apply_filter(GTextfiles[i], outname[0]) == 1) {
  2459.                         if (stat(GTextfiles[i], &file_stat_buf) == -1) {
  2460.                             fclose(tmpfp);
  2461.                             continue;
  2462.                         }
  2463.                         if (!ByteLevelIndex || NOBYTELEVEL || (file_stat_buf.st_mtime > index_stat_buf.st_mtime)) {
  2464.                             first_search = 1;
  2465.                             ret = fileagrep_search(AM, APattern, 1, outname, 0, tmpfp);
  2466.                         }
  2467.                         else {
  2468.                             if (file_stat_buf.st_mtime > index_stat_buf.st_mtime) {
  2469.                                 /* fprintf(stderr, "Warning: file modified after indexing: must SEARCH %s\n", CurrentFileName); */
  2470.                                 free_list(&src_offset_table[GFileIndex[i]]);
  2471.                                 first_search = 1;
  2472.                                 ret = fileagrep_search(AM, APattern, 1, outname, 0, tmpfp);
  2473.                             }
  2474.                             else ret = glimpse_search(AM, APattern, GD_length, GD_pattern, GTextfiles[i], outname[0], GFileIndex[i], src_offset_table, tmpfp);
  2475.                         }
  2476.                         unlink(outname[0]);
  2477.                     }
  2478.                     else {
  2479.                         if (!ByteLevelIndex || NOBYTELEVEL) {
  2480.                             first_search = 1;
  2481.                             ret = fileagrep_search(AM, APattern, 1, >extfiles[i], 0, tmpfp);
  2482.                         }
  2483.                         else {
  2484.                             if (stat(GTextfiles[i], &file_stat_buf) == -1) {
  2485.                                 fclose(tmpfp);
  2486.                                 continue;
  2487.                             }
  2488.                             if (file_stat_buf.st_mtime > index_stat_buf.st_mtime) {
  2489.                                 /* fprintf(stderr, "Warning: file modified after indexing: must SEARCH %s\n", CurrentFileName); */
  2490.                                 free_list(&src_offset_table[GFileIndex[i]]);
  2491.                                 first_search = 1;
  2492.                                 ret = fileagrep_search(AM, APattern, 1, >extfiles[i], 0, tmpfp);
  2493.                             }
  2494.                             else ret = glimpse_search(AM, APattern, GD_length, GD_pattern, GTextfiles[i], GTextfiles[i], GFileIndex[i], src_offset_table, tmpfp);
  2495.                         }
  2496.                     }
  2497.                     SetCurrentFileName = 0;
  2498.                     fflush(tmpfp);
  2499.                     fclose(tmpfp);
  2500.                     tmpfp = NULL;
  2501.                     if ((ret < 0) && (errno == AGREP_ERROR)) break;
  2502. #if    DEBUG
  2503.                     printf("done search\n");
  2504.                     fflush(stdout);
  2505. #endif    /*DEBUG*/
  2506.                     LIMITOUTPUT = OLDLIMITOUTPUT;
  2507.                     LIMITPERFILE = OLDLIMITPERFILE;
  2508.                     LIMITTOTALFILE = OLDLIMITTOTALFILE;
  2509.                     PRINTRECORD = OLDPRINTRECORD;
  2510.                     COUNT = OLDCOUNT;
  2511.                     ret = filter_output(GTextfiles[i], tempfile, GParse, GD_pattern, GD_length, GOUTTAIL, nullfp, StructuredIndex);
  2512.                     gnum_of_matched += (ret > 0) ? ret : 0;
  2513.                     gfiles_matched += (ret > 0) ? 1 : 0;
  2514.                     if (GLIMITOUTPUT > 0) {
  2515.                         if (GLIMITOUTPUT <= gnum_of_matched) break;
  2516.                         LIMITOUTPUT = GLIMITOUTPUT - gnum_of_matched;
  2517.                     }
  2518.                     if (GLIMITTOTALFILE > 0) {
  2519.                         if (GLIMITTOTALFILE <= gfiles_matched) break;
  2520.                         LIMITTOTALFILE = GLIMITTOTALFILE - gfiles_matched;
  2521.                     }
  2522.                     if (glimpse_clientdied) break;
  2523.                     fflush(stdout);
  2524.                 }
  2525.             }
  2526.         }
  2527.         if (errno == AGREP_ERROR) {
  2528.             fprintf(stderr, "%s: error in options or arguments to `agrep'\n", HARVEST_PREFIX);
  2529.         }
  2530.  
  2531.         RETURN(0);
  2532.     }
  2533.     else { /* argc > 0: simply call agrep */
  2534. #if    DEBUG
  2535.         for (i=0; i<agrep_argc; i++)
  2536.             printf("agrep_argv[%d] = %s\n", i, agrep_argv[i]);
  2537. #endif    /*DEBUG*/
  2538.         i = fileagrep(oldargc, oldargv, 0, stdout);
  2539.         RETURN(i);
  2540.     }
  2541. }
  2542. /* end of process_query() */
  2543.  
  2544. /*
  2545.  * Simple function to remove the non-existent files from the set of
  2546.  * files passed onto agrep for search. These are the files which got
  2547.  * DELETED after the index was built (but a fresh index was NOT built).
  2548.  * Redundant since agrep opens them anyway and stat is as bad as open.
  2549.  */
  2550. int
  2551. purge_filenames(filenames, num)
  2552.     CHAR    **filenames;
  2553.     int    num;
  2554. {
  2555.     struct stat    buf;
  2556.     int        i, j;
  2557.     int        newnum = num;
  2558.     int        ret;
  2559.  
  2560.     for (i=0; i<newnum; i++) {
  2561.         if (-1 == (ret = stat(filenames[i], &buf))) {
  2562. #if    BG_DEBUG
  2563.             fprintf(debug, "stat on %s = %d\n", filenames[i], ret);
  2564. #endif    /*BG_DEBUG*/
  2565.             my_free(filenames[i], 0);
  2566.             for (j=i; j<newnum-1; j++)
  2567.                 filenames[j] = filenames[j+1];
  2568.             filenames[j] = NULL;
  2569.             newnum --;
  2570.             i--;    /* to counter the ++ on top */
  2571.         }
  2572.     }
  2573.  
  2574. #if    BG_DEBUG
  2575.     fprintf(debug, "Old numfiles=%d\tNew numfiles=%d\n", num, newnum);
  2576.     for (i=0; i<newnum; i++)
  2577.         fprintf(debug, "file %d = %s\n", i, filenames[i]);
  2578. #endif    /*BG_DEBUG*/
  2579.     return newnum;
  2580. }
  2581.  
  2582. CHAR filter_buf[BLOCKSIZE + MAXPAT*2];
  2583.  
  2584. /* returns #of bytes stripped off */
  2585. int getbyteoff(buf, pbyteoff)
  2586.     CHAR    *buf;
  2587.     int    *pbyteoff;
  2588. {
  2589.     CHAR    temp[32];
  2590.     int    i = 0;
  2591.  
  2592.     while (isdigit(*buf) && (i<32)) temp[i++] = *buf++;
  2593.     if ((*buf != '=') || (*(buf + 1) != ' ')) return -1;
  2594.     temp[i] = '\0';
  2595.     *pbyteoff = atoi(temp);
  2596.     return i+2;
  2597. }
  2598.  
  2599. /*
  2600.  * Filter the output in infile:
  2601.  *
  2602.  * -- get the matched line/record-s using GD_pattern, GD_length and GOUTAIL
  2603.  * -- call identify regions using matched line/record's byte offset
  2604.  * -- collect patterns corr. to that attribute into a new pattern (in split_pat itself)
  2605.  * -- see if one of them matches that line/record using memagrep
  2606.  * -- if so, output that line/record onto stdout
  2607.  */
  2608. int
  2609. filter_output(infile, outfile, GParse, GD_pattern, GD_length, GOUTTAIL, nullfp, num_attr)
  2610.     char    *infile;
  2611.     char    *outfile;
  2612.     ParseTree *GParse;
  2613.     CHAR    GD_pattern[];
  2614.     int    GD_length[];
  2615.     int    GOUTTAIL;
  2616.     FILE    *nullfp;
  2617.     int    num_attr;
  2618. {
  2619.     FILE    *outfp;
  2620.     FILE    *displayfp = NULL;
  2621.     FILE    *storefp = NULL;
  2622.     int    num_read;
  2623.     int    residue = 0;
  2624.     int    byteoff;
  2625.     int    attribute;
  2626.     int    i, ii;    /* i is forloop index, ii is booleaneval index */
  2627.     CHAR    *final_end;
  2628.     CHAR    *current_end;
  2629.     CHAR    *current_begin;
  2630.     CHAR    *previous_begin;
  2631.     int    skiplen;
  2632.     char    s[MAX_LINE_LEN];
  2633.     CHAR    c1, c2;
  2634.     int    printed, numprinted = 0;    /* returns number of printed records if successful in matching the pattern in the object infile */
  2635.     char    *attrname;
  2636.     int    success = 0;    /* do we print the stored output or not */
  2637.     int    count = 0;
  2638.  
  2639. #if    BG_DEBUG
  2640.     printf("INFILE=%s\n", infile);
  2641.     printf("OUTFILE\n");
  2642.     sprintf(s, "exec cat %s\n", outfile);
  2643.     system(s);
  2644. #endif    /*BG_DEBUG*/
  2645.     if ((outfp = fopen(outfile, "r")) == NULL) return 0;
  2646.     if (StructuredIndex && (-1 == region_create(infile))) {
  2647.         fclose(outfp);
  2648.         return 0;
  2649.     }
  2650.     if (ComplexBoolean || ((long)GParse & AND_EXP)) {
  2651.         sprintf(s, "%s/.glimpse_storeoutput.%d", TEMP_DIR, getpid());
  2652.         if ((displayfp = storefp = fopen(s, "w")) == NULL) {
  2653.             if (StructuredIndex) region_destroy();
  2654.             fclose(outfp);
  2655.             return 0;
  2656.         }
  2657.     }
  2658.     else {
  2659.         displayfp = stdout;
  2660.         /* cannot come to filter_output in this case unless -a! */
  2661.     }
  2662.     memset(matched_terminals, '\0', num_terminals);
  2663.  
  2664.     while ( ( (num_read = fread(filter_buf + residue, 1, BLOCKSIZE - residue, outfp)) > 0) || (residue > 0)) {
  2665.         if (num_read <= 0) {
  2666.             final_end = filter_buf + residue;
  2667.             num_read = residue;
  2668.             residue = 0;
  2669.         }
  2670.         else {
  2671.             num_read += residue;
  2672.             final_end = (CHAR *)backward_delimiter(filter_buf + num_read, filter_buf, GD_pattern, GD_length, GOUTTAIL);
  2673.             residue = filter_buf + num_read - final_end;
  2674.         }
  2675. #if    DEBUG
  2676.         fprintf(stderr, "filter_buf=%x final_end=%x residue=%x last_chars=%c%c%c num_read=%x\n",
  2677.             filter_buf, final_end, residue, *(final_end-2), *(final_end-1), *(final_end), num_read);
  2678. #endif    /*DEBUG*/
  2679.  
  2680.         current_begin = previous_begin = filter_buf;
  2681.         current_end = (CHAR *)forward_delimiter(filter_buf, filter_buf + num_read, GD_pattern, GD_length, GOUTTAIL);    /* skip over prefixes like filename */
  2682.         if (!GOUTTAIL) current_end = (CHAR *)forward_delimiter((long)current_end + GD_length, final_end, GD_pattern, GD_length, GOUTTAIL);
  2683.  
  2684.         while (current_end <= final_end) {
  2685.             previous_begin = current_begin;
  2686.             /* look for %d= */
  2687.             byteoff = -1;
  2688.             while (current_begin < current_end) {
  2689.                 if (isdigit(*current_begin)) {
  2690.                     skiplen = getbyteoff(current_begin, &byteoff);
  2691. #if    BG_DEBUG
  2692.                     fprintf(debug, "byteoff=%d skiplen=%d\n", byteoff, skiplen);
  2693. #endif    /*BG_DEBUG*/
  2694.                     if ((skiplen < 0) || (byteoff < 0)) {
  2695.                         current_begin ++;
  2696.                         continue;
  2697.                     }
  2698.                     else break;
  2699.                 }
  2700.                 else current_begin ++;
  2701.             }
  2702. #if    DEBUG
  2703.             printf("current_begin=%x current_end=%x final_end=%x residue=%x num_read=%x\n", current_begin, current_end, final_end, residue, num_read);
  2704. #endif    /*DEBUG*/
  2705.  
  2706. #if    DEBUG
  2707.             printf("byteoff=%d skiplen=%d\n", byteoff, skiplen);
  2708. #endif    /*DEBUG*/
  2709.             if ((skiplen < 0) || (byteoff < 0)) {    /* output the whole line as it is: there is nothing to strip (e.g., -l) */
  2710.                 fwrite(previous_begin, 1, current_end-previous_begin, displayfp);
  2711.                 numprinted ++;
  2712.             }
  2713.             else if ( (num_attr <= 0) || (((attribute = region_identify(byteoff, 0)) < num_attr) && (attribute >= 0)) ) {
  2714.                 /* prefix is from previous_begin to current_begin. Skip skiplen from current_begin. Rest until current_end is valid output */
  2715.                 if (num_attr <= 0) attribute = 0;
  2716. #if    BG_DEBUG
  2717.                 fprintf(debug, "region@%d=%d\n", byteoff, attribute);
  2718. #endif    /*BG_DEBUG*/
  2719.                 c1 = *(current_begin + skiplen - 1);
  2720.                 c2 = *(current_end + 1);
  2721.                 printed = 0;
  2722.  
  2723.                 for (i=0; i<num_terminals; i++) {
  2724.                     if (matched_terminals[i] && (GFILENAMEONLY || FILEOUT || printed || ((LIMITOUTPUT > 0) && (numprinted >= LIMITOUTPUT)) || ((LIMITPERFILE > 0) && (numprinted >= LIMITPERFILE)))) continue;
  2725.  
  2726.                     if ((terminals[i].data.leaf.attribute == 0)  || ((int)(terminals[i].data.leaf.attribute) == attribute)) {
  2727.                         *(current_begin + skiplen - 1) = '\n';
  2728.                         *(current_end + 1) = '\n';
  2729.                         if (memagrep_search(    strlen(terminals[i].data.leaf.value), terminals[i].data.leaf.value,
  2730.                                     current_end - current_begin - skiplen + 1, current_begin + skiplen - 1,
  2731.                                     0, nullfp) > 0) {
  2732. #if    0
  2733.                             *(current_end + 1) = '\0';
  2734.                             printf("--> search succeeded for %s in %s\n", terminals[i].data.leaf.value, previous_begin);
  2735. #endif    /*0*/
  2736.                             *(current_begin + skiplen - 1) = c1;
  2737.                             *(current_end + 1) = c2;
  2738.                             matched_terminals[i] = 1;    /* must reevaluate/set since don't know if it should be printed */
  2739.  
  2740.                             if (!(((LIMITOUTPUT > 0) && (numprinted >= LIMITOUTPUT)) ||
  2741.                                   ((LIMITPERFILE > 0) && (numprinted >= LIMITPERFILE))) && !printed) {    /* see if it was useful later */
  2742.                                 if (!COUNT && !FILEOUT) {
  2743.                                 fwrite(previous_begin, 1, current_begin - previous_begin, displayfp);
  2744.                                 if (PRINTATTR) fprintf(displayfp, "%s# ",
  2745.                                     (attrname = attr_id_to_name(attribute)) == NULL ? "(null)" : attrname);
  2746.                                 if (GBYTECOUNT) fprintf(displayfp, "%d= ", byteoff);
  2747.                                 if (PRINTRECORD) {
  2748.                                 fwrite(current_begin + skiplen, 1, current_end - current_begin - skiplen, displayfp);
  2749.                                 }
  2750.                                 else {
  2751.                                     if (*(current_begin + skiplen) == '@') {
  2752.                                         int    iii = 0;
  2753.                                         while (current_begin[skiplen + iii] != '}')
  2754.                                             fputc(current_begin[skiplen + iii++], displayfp);
  2755.                                         fputc('}', displayfp);
  2756.                                     }
  2757.                                     fputc('\n', displayfp);
  2758.                                 }
  2759.                                 }
  2760.                                 printed = 1;
  2761.                                 numprinted ++;
  2762.                             }
  2763.                         }
  2764.                         else {
  2765. #if    0
  2766.                             *(current_end + 1) = '\0';
  2767.                             printf("--> search failed for %s in %s\n", terminals[i].data.leaf.value, previous_begin);
  2768. #endif    /*0*/
  2769.                             *(current_begin + skiplen - 1) = c1;
  2770.                             *(current_end + 1) = c2;
  2771.                         }
  2772.                     }
  2773.                 }
  2774.  
  2775.                 if (!success) {
  2776.                     if (ComplexBoolean) {
  2777.                         success = eval_tree(GParse, matched_terminals);
  2778.                     }
  2779.                     else {
  2780.                         if ((long)GParse & AND_EXP) {
  2781.                             success = 0;
  2782.                             for (ii=0; ii<num_terminals; ii++) {
  2783.                                 if (!matched_terminals[ii]) break;
  2784.                             }
  2785.                             if (ii >= num_terminals) success = 1;
  2786.                         }
  2787.                         else {
  2788.                             success = 0;
  2789.                             /* cannot come to filter_output in this case unless -a! */
  2790.                         }
  2791.                     }
  2792.                 }
  2793.  
  2794.                 /* optimize options that do not need all the matched lines */
  2795.                 if (success) {
  2796.                     if (GFILENAMEONLY) {
  2797.                         fprintf(stdout, "%s\n", infile);
  2798.                         if (storefp != NULL) fclose(storefp); /* don't bother to flush! */
  2799.                         storefp = NULL;
  2800.                         goto unlink_and_quit;
  2801.                     }
  2802.                     else if (FILEOUT) {
  2803.                         file_out(infile);
  2804.                         if (storefp != NULL) fclose(storefp); /* don't bother to flush! */
  2805.                         storefp = NULL;
  2806.                         goto unlink_and_quit;
  2807.                     }
  2808.                 }
  2809.             }
  2810.             if (((LIMITOUTPUT > 0) && (numprinted >= LIMITOUTPUT)) || ((LIMITPERFILE > 0) && (numprinted >= LIMITPERFILE))) goto double_break;
  2811.             if (glimpse_clientdied) goto double_break;
  2812.             if (current_end >= final_end) break;
  2813.             current_begin = current_end;
  2814.             if (!GOUTTAIL) current_end = (CHAR *)forward_delimiter((long)current_end + GD_length, final_end, GD_pattern, GD_length, GOUTTAIL);
  2815.             else current_end = (CHAR *)forward_delimiter(current_end, final_end, GD_pattern, GD_length, GOUTTAIL);
  2816.         }
  2817.         if (residue > 0) memcpy(filter_buf, final_end, residue);
  2818.     }
  2819.  
  2820. double_break:
  2821.     /* Come here on normal exit or when the current agrep-output is no longer of any use */
  2822.     if (!success) {
  2823.         if (ComplexBoolean) {
  2824.             success = eval_tree(GParse, matched_terminals);
  2825.         }
  2826.         else {
  2827.             if ((long)GParse & AND_EXP) {
  2828.                 success = 0;
  2829.                 for (ii=0; ii<num_terminals; ii++) {
  2830.                     if (!matched_terminals[ii]) break;
  2831.                 }
  2832.                 if (ii >= num_terminals) success = 1;
  2833.             }
  2834.             else {
  2835.                 success = 0;
  2836.                 /* cannot come to filter_output in this case unless -a! */
  2837.             }
  2838.         }
  2839.     }
  2840.  
  2841.     /* Print the temporary output onto stdout if search was successful; unlink the temprorary file */
  2842.     if (success) {
  2843.         if (GFILENAMEONLY) {    /* all other output options are useless since they all deal with the MATCHED line */
  2844.             fprintf(stdout, "%s\n", infile);
  2845.             if (storefp != NULL) fclose(storefp); /* don't bother to flush! */
  2846.             storefp = NULL;
  2847.         }
  2848.         else if (COUNT && !FILEOUT) {
  2849.             if(!NOFILENAME) fprintf(stdout, "%s: %d\n", CurrentFileName, numprinted);
  2850.             else fprintf(stdout, "%d\n", numprinted);
  2851.             if (storefp != NULL) fclose(storefp); /* don't bother to flush! */
  2852.             storefp = NULL;
  2853.         }
  2854.         else if (FILEOUT) {
  2855.             file_out(infile);
  2856.             if (storefp != NULL) fclose(storefp); /* don't bother to flush! */
  2857.             storefp = NULL;
  2858.         }
  2859.         else if (storefp != NULL) {
  2860.             fflush(storefp);
  2861.             fclose(storefp);
  2862. #if    DEBUG
  2863.             printf("STOREOUTPUT\n");
  2864.             sprintf(s, "exec cat %s/.glimpse_storeoutput.%d\n", TEMP_DIR, getpid());
  2865.             system(s);
  2866. #endif    /*DEBUG*/
  2867.             sprintf(s, "%s/.glimpse_storeoutput.%d", TEMP_DIR, getpid());
  2868.             if ((storefp = fopen(s, "r")) != NULL) {
  2869.                 while (fgets(s, MAX_LINE_LEN, storefp) != NULL) fputs(s, stdout);
  2870.                 fclose(storefp);
  2871.             }
  2872.             storefp = NULL;
  2873.         }
  2874.     }
  2875.     else {
  2876.         if (storefp != NULL) fclose(storefp); /* else don't bother to flush */
  2877.     }
  2878.  
  2879. unlink_and_quit:
  2880.     sprintf(s, "%s/.glimpse_storeoutput.%d", TEMP_DIR, getpid());
  2881.     unlink(s);
  2882.  
  2883.     if (StructuredIndex) region_destroy();
  2884.     fclose(outfp);
  2885.  
  2886.     if (GFILENAMEONLY) {
  2887.         if (numprinted > 0) return 1;
  2888.         else return 0;
  2889.     }
  2890.     else if (ComplexBoolean || ((long)GParse & AND_EXP)) {
  2891.         if (success) return numprinted;
  2892.         else return 0;
  2893.     } else {    /* must be -a */
  2894.         return numprinted;
  2895.     }
  2896. }
  2897.  
  2898. usage()
  2899. {
  2900.     fprintf(stderr, "\nThis is glimpse version %s, %s.\n\n", GLIMPSE_VERSION, GLIMPSE_DATE);
  2901.     fprintf(stderr, "usage:  %s [-#abcdehiklnprstwxyBCDEGIMNQSVW] [-F pat] [-H dir] [-J host] [-K port] [-L num] [-R lim] [-T dir] pattern [files]", GProgname);
  2902.     fprintf(stderr, "\n");
  2903.     fprintf(stderr, "summary of frequently used options:\n");
  2904.     fprintf(stderr, "(For a more detailed listing see 'man glimpse'.)\n");
  2905.     fprintf(stderr, "-#: find matches with at most # errors\n");
  2906.     fprintf(stderr, "-c: output the number of matched records\n");
  2907.     fprintf(stderr, "-d: define record delimiter\n");
  2908.     fprintf(stderr, "-h: do not output file names\n");
  2909.     fprintf(stderr, "-i: case-insensitive search, e.g., 'a' = 'A'\n");
  2910.     fprintf(stderr, "-l: output the names of files that contain a match\n");
  2911.     fprintf(stderr, "-n: output record prefixed by record number\n");
  2912.     /* fprintf(stderr, "-v: output those records that have no matches\n"); */
  2913.     fprintf(stderr, "-w: pattern has to match as a word, e.g., 'win' will not match 'wind'\n");
  2914.     fprintf(stderr, "-B: best match mode. find the closest matches to the pattern\n");
  2915.     fprintf(stderr, "-F 'pat': 'pat' is used to match against file names\n");
  2916.     fprintf(stderr, "-G: output the (whole) files that contain a match\n");
  2917.     fprintf(stderr, "-H 'dir': the glimpse index is located in directory 'dir'\n");
  2918.     fprintf(stderr, "-L 'num': limit the output to 'num' records only\n");
  2919.     fprintf(stderr, "\n");
  2920.     fprintf(stderr, "For questions about glimpse, please contact `%s'\n", GLIMPSE_EMAIL);
  2921.  
  2922.     return -1;    /* useful if we make glimpse into a library */
  2923.  
  2924. /*
  2925.  * Undocumented Options for SFS (like RPC calls)
  2926.  *    print file number of match instead of file name: -g
  2927.  *    print enclosing offsets of matched record: -q
  2928.  *    NOT print matched record: -u
  2929.  * E.G. USAGE: -qbug (b prints offset of pattern: can also use -lg or -Ng)
  2930.  *    look only at index: -E
  2931.  *    look at matched offsets in files as seen in index (w/o searching): -QN
  2932.  * E.G. USAGE: -EQNgy
  2933.  *    read the -EQNg or just -QNg output from stdin and perform actual search w/o
  2934.  *    searching the index (take hints from user): -U
  2935.  * NOTE: can't use U unless QNg are all used together (e.g., BEGIN/END won't be printed)
  2936.  */
  2937. }
  2938.  
  2939. usageS()
  2940. {
  2941.     fprintf(stderr, "\nThis is glimpse server version %s, %s.\n\n", GLIMPSE_VERSION, GLIMPSE_DATE);
  2942.     fprintf(stderr, "usage:  %s [-H dir] [-J host] [-K port]", GProgname);
  2943.     fprintf(stderr, "\n");
  2944.     fprintf(stderr, "-H 'dir': the glimpse index is located in directory 'dir'\n");
  2945.     fprintf(stderr, "-J 'host': the host name (string) clients must use / server runs on \n");
  2946.     fprintf(stderr, "-K 'port': the port (short integer) clients must use / server runs on \n");
  2947.     fprintf(stderr, "\n");
  2948.     fprintf(stderr, "For questions about glimpse, please contact `%s'\n", GLIMPSE_EMAIL);
  2949.  
  2950.     return -1;    /* useful if we make glimpse into a library */
  2951. }
  2952.  
  2953. #if    CLIENTSERVER
  2954. /*
  2955.  *  do_select() - based on select_loop() from the Harvest Broker.
  2956.  *  -- Courtesy: Darren Hardy, hardy@cs.colorado.edu
  2957.  */
  2958. int do_select(sock, sec)
  2959. int sock;        /* the socket to wait for */
  2960. int sec;        /* the number of seconds to wait */
  2961. {
  2962.     struct timeval to;
  2963.     fd_set qready;
  2964.     int err;
  2965.  
  2966.     if (sock < 0 || sec < 0)
  2967.         return 0;
  2968.  
  2969.     FD_ZERO(&qready);
  2970.     FD_SET(sock, &qready);
  2971.     to.tv_sec = sec;
  2972.     to.tv_usec = 0;
  2973.     if ((err = select(sock + 1, &qready, NULL, NULL, &to)) < 0) {
  2974.         if (errno == EINTR)
  2975.             return 0;
  2976.         perror("select");
  2977.         return -1;
  2978.     }
  2979.     if (err == 0)
  2980.         return 0;
  2981.  
  2982.     /* If there's someone waiting to get it, let them through */
  2983.     return (FD_ISSET(sock, &qready) ? 1 : 0);
  2984. }
  2985. #endif    /* CLIENTSERVER */
  2986.